about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Navigation.tsx9
-rw-r--r--src/components/forms/ToggleButton.tsx2
-rw-r--r--src/components/icons/Moon.tsx5
-rw-r--r--src/components/icons/Phone.tsx5
-rw-r--r--src/lib/routes/types.ts1
-rw-r--r--src/routes.ts1
-rw-r--r--src/screens/Settings/AppearanceSettings.tsx135
-rw-r--r--src/view/icons/index.tsx2
-rw-r--r--src/view/screens/AccessibilitySettings.tsx10
-rw-r--r--src/view/screens/PreferencesExternalEmbeds.tsx5
-rw-r--r--src/view/screens/PreferencesFollowingFeed.tsx5
-rw-r--r--src/view/screens/PreferencesThreads.tsx4
-rw-r--r--src/view/screens/Settings/index.tsx95
13 files changed, 201 insertions, 78 deletions
diff --git a/src/Navigation.tsx b/src/Navigation.tsx
index 8646577c8..79856879c 100644
--- a/src/Navigation.tsx
+++ b/src/Navigation.tsx
@@ -44,6 +44,7 @@ import HashtagScreen from '#/screens/Hashtag'
 import {ModerationScreen} from '#/screens/Moderation'
 import {ProfileKnownFollowersScreen} from '#/screens/Profile/KnownFollowers'
 import {ProfileLabelerLikedByScreen} from '#/screens/Profile/ProfileLabelerLikedBy'
+import {AppearanceSettingsScreen} from '#/screens/Settings/AppearanceSettings'
 import {
   StarterPackScreen,
   StarterPackScreenShort,
@@ -311,6 +312,14 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
         }}
       />
       <Stack.Screen
+        name="AppearanceSettings"
+        getComponent={() => AppearanceSettingsScreen}
+        options={{
+          title: title(msg`Appearance Settings`),
+          requireAuth: true,
+        }}
+      />
+      <Stack.Screen
         name="Hashtag"
         getComponent={() => HashtagScreen}
         options={{title: title(msg`Hashtag`)}}
diff --git a/src/components/forms/ToggleButton.tsx b/src/components/forms/ToggleButton.tsx
index 752842638..f47a272b1 100644
--- a/src/components/forms/ToggleButton.tsx
+++ b/src/components/forms/ToggleButton.tsx
@@ -23,10 +23,10 @@ export function Group({children, multiple, ...props}: GroupProps) {
         style={[
           a.w_full,
           a.flex_row,
-          a.border,
           a.rounded_sm,
           a.overflow_hidden,
           t.atoms.border_contrast_low,
+          {borderWidth: 1},
         ]}>
         {children}
       </View>
diff --git a/src/components/icons/Moon.tsx b/src/components/icons/Moon.tsx
new file mode 100644
index 000000000..4994370b9
--- /dev/null
+++ b/src/components/icons/Moon.tsx
@@ -0,0 +1,5 @@
+import {createSinglePathSVG} from './TEMPLATE'
+
+export const Moon_Stroke2_Corner0_Rounded = createSinglePathSVG({
+  path: 'M12.097 2.53a1 1 0 0 1-.041 1.07 6 6 0 0 0 8.345 8.344 1 1 0 0 1 1.563.908c-.434 5.122-4.728 9.144-9.962 9.144-5.522 0-9.998-4.476-9.998-9.998 0-5.234 4.021-9.528 9.144-9.962a1 1 0 0 1 .949.494ZM9.424 4.424a7.998 7.998 0 1 0 10.152 10.152A8 8 0 0 1 9.424 4.424Z',
+})
diff --git a/src/components/icons/Phone.tsx b/src/components/icons/Phone.tsx
new file mode 100644
index 000000000..62000a1e5
--- /dev/null
+++ b/src/components/icons/Phone.tsx
@@ -0,0 +1,5 @@
+import {createSinglePathSVG} from './TEMPLATE'
+
+export const Phone_Stroke2_Corner0_Rounded = createSinglePathSVG({
+  path: 'M5 4a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H8a3 3 0 0 1-3-3V4Zm3-1a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H8Zm2 2a1 1 0 0 1 1-1h2a1 1 0 1 1 0 2h-2a1 1 0 0 1-1-1Z',
+})
diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts
index fbb66c9e9..0cc83b475 100644
--- a/src/lib/routes/types.ts
+++ b/src/lib/routes/types.ts
@@ -38,6 +38,7 @@ export type CommonNavigatorParams = {
   PreferencesThreads: undefined
   PreferencesExternalEmbeds: undefined
   AccessibilitySettings: undefined
+  AppearanceSettings: undefined
   Search: {q?: string}
   Hashtag: {tag: string; author?: string}
   MessagesConversation: {conversation: string; embed?: string}
diff --git a/src/routes.ts b/src/routes.ts
index ddf4fb39f..c9e23e08c 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -32,6 +32,7 @@ export const router = new Router({
   PreferencesThreads: '/settings/threads',
   PreferencesExternalEmbeds: '/settings/external-embeds',
   AccessibilitySettings: '/settings/accessibility',
+  AppearanceSettings: '/settings/appearance',
   SavedFeeds: '/settings/saved-feeds',
   Support: '/support',
   PrivacyPolicy: '/support/privacy',
diff --git a/src/screens/Settings/AppearanceSettings.tsx b/src/screens/Settings/AppearanceSettings.tsx
new file mode 100644
index 000000000..00a04bbfb
--- /dev/null
+++ b/src/screens/Settings/AppearanceSettings.tsx
@@ -0,0 +1,135 @@
+import React, {useCallback} from 'react'
+import {View} from 'react-native'
+import Animated, {
+  FadeInDown,
+  FadeOutDown,
+  LayoutAnimationConfig,
+} from 'react-native-reanimated'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
+import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
+import {s} from '#/lib/styles'
+import {useSetThemePrefs, useThemePrefs} from '#/state/shell'
+import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
+import {ScrollView} from '#/view/com/util/Views'
+import {atoms as a, native, useTheme} from '#/alf'
+import * as ToggleButton from '#/components/forms/ToggleButton'
+import {Moon_Stroke2_Corner0_Rounded as MoonIcon} from '#/components/icons/Moon'
+import {Phone_Stroke2_Corner0_Rounded as PhoneIcon} from '#/components/icons/Phone'
+import {Text} from '#/components/Typography'
+
+type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppearanceSettings'>
+export function AppearanceSettingsScreen({}: Props) {
+  const {_} = useLingui()
+  const t = useTheme()
+  const {isTabletOrMobile} = useWebMediaQueries()
+
+  const {colorMode, darkTheme} = useThemePrefs()
+  const {setColorMode, setDarkTheme} = useSetThemePrefs()
+
+  const onChangeAppearance = useCallback(
+    (keys: string[]) => {
+      const appearance = keys.find(key => key !== colorMode) as
+        | 'system'
+        | 'light'
+        | 'dark'
+        | undefined
+      if (!appearance) return
+      setColorMode(appearance)
+    },
+    [setColorMode, colorMode],
+  )
+
+  const onChangeDarkTheme = useCallback(
+    (keys: string[]) => {
+      const theme = keys.find(key => key !== darkTheme) as
+        | 'dim'
+        | 'dark'
+        | undefined
+      if (!theme) return
+      setDarkTheme(theme)
+    },
+    [setDarkTheme, darkTheme],
+  )
+
+  return (
+    <LayoutAnimationConfig skipExiting skipEntering>
+      <View testID="preferencesThreadsScreen" style={s.hContentRegion}>
+        <ScrollView
+          // @ts-ignore web only -prf
+          dataSet={{'stable-gutters': 1}}
+          contentContainerStyle={{paddingBottom: 75}}>
+          <SimpleViewHeader
+            showBackButton={isTabletOrMobile}
+            style={[t.atoms.border_contrast_medium, a.border_b]}>
+            <View style={a.flex_1}>
+              <Text style={[a.text_2xl, a.font_bold]}>
+                <Trans>Appearance</Trans>
+              </Text>
+            </View>
+          </SimpleViewHeader>
+
+          <View style={[a.p_xl, a.gap_lg]}>
+            <View style={[a.flex_row, a.align_center, a.gap_md]}>
+              <PhoneIcon style={t.atoms.text} />
+              <Text style={a.text_md}>
+                <Trans>Mode</Trans>
+              </Text>
+            </View>
+            <ToggleButton.Group
+              label={_(msg`Dark mode`)}
+              values={[colorMode]}
+              onChange={onChangeAppearance}>
+              <ToggleButton.Button label={_(msg`System`)} name="system">
+                <ToggleButton.ButtonText>
+                  <Trans>System</Trans>
+                </ToggleButton.ButtonText>
+              </ToggleButton.Button>
+              <ToggleButton.Button label={_(msg`Light`)} name="light">
+                <ToggleButton.ButtonText>
+                  <Trans>Light</Trans>
+                </ToggleButton.ButtonText>
+              </ToggleButton.Button>
+              <ToggleButton.Button label={_(msg`Dark`)} name="dark">
+                <ToggleButton.ButtonText>
+                  <Trans>Dark</Trans>
+                </ToggleButton.ButtonText>
+              </ToggleButton.Button>
+            </ToggleButton.Group>
+            {colorMode !== 'light' && (
+              <Animated.View
+                entering={native(FadeInDown)}
+                exiting={native(FadeOutDown)}
+                style={[a.mt_md, a.gap_lg]}>
+                <View style={[a.flex_row, a.align_center, a.gap_md]}>
+                  <MoonIcon style={t.atoms.text} />
+                  <Text style={a.text_md}>
+                    <Trans>Dark theme</Trans>
+                  </Text>
+                </View>
+
+                <ToggleButton.Group
+                  label={_(msg`Dark theme`)}
+                  values={[darkTheme ?? 'dim']}
+                  onChange={onChangeDarkTheme}>
+                  <ToggleButton.Button label={_(msg`Dim`)} name="dim">
+                    <ToggleButton.ButtonText>
+                      <Trans>Dim</Trans>
+                    </ToggleButton.ButtonText>
+                  </ToggleButton.Button>
+                  <ToggleButton.Button label={_(msg`Dark`)} name="dark">
+                    <ToggleButton.ButtonText>
+                      <Trans>Dark</Trans>
+                    </ToggleButton.ButtonText>
+                  </ToggleButton.Button>
+                </ToggleButton.Group>
+              </Animated.View>
+            )}
+          </View>
+        </ScrollView>
+      </View>
+    </LayoutAnimationConfig>
+  )
+}
diff --git a/src/view/icons/index.tsx b/src/view/icons/index.tsx
index beb31eca4..8b1655e6a 100644
--- a/src/view/icons/index.tsx
+++ b/src/view/icons/index.tsx
@@ -77,6 +77,7 @@ import {faListUl} from '@fortawesome/free-solid-svg-icons/faListUl'
 import {faLock} from '@fortawesome/free-solid-svg-icons/faLock'
 import {faMagnifyingGlass} from '@fortawesome/free-solid-svg-icons/faMagnifyingGlass'
 import {faNoteSticky} from '@fortawesome/free-solid-svg-icons/faNoteSticky'
+import {faPaintRoller} from '@fortawesome/free-solid-svg-icons/faPaintRoller'
 import {faPause} from '@fortawesome/free-solid-svg-icons/faPause'
 import {faPen} from '@fortawesome/free-solid-svg-icons/faPen'
 import {faPenNib} from '@fortawesome/free-solid-svg-icons/faPenNib'
@@ -178,6 +179,7 @@ library.add(
   faMagnifyingGlass,
   faMessage,
   faNoteSticky,
+  faPaintRoller,
   faPaste,
   faPause,
   faPen,
diff --git a/src/view/screens/AccessibilitySettings.tsx b/src/view/screens/AccessibilitySettings.tsx
index abe155076..2a4477532 100644
--- a/src/view/screens/AccessibilitySettings.tsx
+++ b/src/view/screens/AccessibilitySettings.tsx
@@ -27,6 +27,7 @@ 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 {atoms as a} from '#/alf'
 
 type Props = NativeStackScreenProps<
   CommonNavigatorParams,
@@ -61,10 +62,13 @@ export function AccessibilitySettingsScreen({}: Props) {
         showBackButton={isTabletOrMobile}
         style={[
           pal.border,
-          {borderBottomWidth: 1},
-          !isMobile && {borderLeftWidth: 1, borderRightWidth: 1},
+          a.border_b,
+          !isMobile && {
+            borderLeftWidth: StyleSheet.hairlineWidth,
+            borderRightWidth: StyleSheet.hairlineWidth,
+          },
         ]}>
-        <View style={{flex: 1}}>
+        <View style={a.flex_1}>
           <Text type="title-lg" style={[pal.text, {fontWeight: 'bold'}]}>
             <Trans>Accessibility Settings</Trans>
           </Text>
diff --git a/src/view/screens/PreferencesExternalEmbeds.tsx b/src/view/screens/PreferencesExternalEmbeds.tsx
index 57ca5e765..ade7a53d9 100644
--- a/src/view/screens/PreferencesExternalEmbeds.tsx
+++ b/src/view/screens/PreferencesExternalEmbeds.tsx
@@ -18,6 +18,7 @@ import {
   useSetExternalEmbedPref,
 } from 'state/preferences'
 import {ToggleButton} from 'view/com/util/forms/ToggleButton'
+import {atoms as a} from '#/alf'
 import {SimpleViewHeader} from '../com/util/SimpleViewHeader'
 import {Text} from '../com/util/text/Text'
 import {ScrollView} from '../com/util/Views'
@@ -47,8 +48,8 @@ export function PreferencesExternalEmbeds({}: Props) {
         contentContainerStyle={[pal.viewLight, {paddingBottom: 75}]}>
         <SimpleViewHeader
           showBackButton={isTabletOrMobile}
-          style={[pal.border, {borderBottomWidth: 1}]}>
-          <View style={{flex: 1}}>
+          style={[pal.border, a.border_b]}>
+          <View style={a.flex_1}>
             <Text type="title-lg" style={[pal.text, {fontWeight: 'bold'}]}>
               <Trans>External Media Preferences</Trans>
             </Text>
diff --git a/src/view/screens/PreferencesFollowingFeed.tsx b/src/view/screens/PreferencesFollowingFeed.tsx
index 879c925fb..daa2aba85 100644
--- a/src/view/screens/PreferencesFollowingFeed.tsx
+++ b/src/view/screens/PreferencesFollowingFeed.tsx
@@ -19,6 +19,7 @@ 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 {atoms as a} from '#/alf'
 
 function RepliesThresholdInput({
   enabled,
@@ -99,8 +100,8 @@ export function PreferencesFollowingFeed({}: Props) {
         contentContainerStyle={{paddingBottom: 75}}>
         <SimpleViewHeader
           showBackButton={isTabletOrMobile}
-          style={[pal.border, {borderBottomWidth: 1}]}>
-          <View style={{flex: 1}}>
+          style={[pal.border, a.border_b]}>
+          <View style={a.flex_1}>
             <Text type="title-lg" style={[pal.text, {fontWeight: 'bold'}]}>
               <Trans>Following Feed Preferences</Trans>
             </Text>
diff --git a/src/view/screens/PreferencesThreads.tsx b/src/view/screens/PreferencesThreads.tsx
index 3b09f0abb..4a311f91c 100644
--- a/src/view/screens/PreferencesThreads.tsx
+++ b/src/view/screens/PreferencesThreads.tsx
@@ -45,8 +45,8 @@ export function PreferencesThreads({}: Props) {
         contentContainerStyle={{paddingBottom: 75}}>
         <SimpleViewHeader
           showBackButton={isTabletOrMobile}
-          style={[pal.border, {borderBottomWidth: 1}]}>
-          <View style={{flex: 1}}>
+          style={[pal.border, a.border_b]}>
+          <View style={a.flex_1}>
             <Text type="title-lg" style={[pal.text, {fontWeight: 'bold'}]}>
               <Trans>Thread Preferences</Trans>
             </Text>
diff --git a/src/view/screens/Settings/index.tsx b/src/view/screens/Settings/index.tsx
index db74d5c0d..c33be7d54 100644
--- a/src/view/screens/Settings/index.tsx
+++ b/src/view/screens/Settings/index.tsx
@@ -31,12 +31,7 @@ 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,
-  useSetThemePrefs,
-  useThemePrefs,
-} from '#/state/shell'
+import {useOnboardingDispatch, useSetMinimalShellMode} from '#/state/shell'
 import {useLoggedOutViewControls} from '#/state/shell/logged-out'
 import {useCloseAllActiveElements} from '#/state/util'
 import {useAnalytics} from 'lib/analytics/analytics'
@@ -52,7 +47,6 @@ import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
 import {NavigationProp} from 'lib/routes/types'
 import {colors, s} from 'lib/styles'
 import {AccountDropdownBtn} from 'view/com/util/AccountDropdownBtn'
-import {SelectableBtn} from 'view/com/util/forms/SelectableBtn'
 import {ToggleButton} from 'view/com/util/forms/ToggleButton'
 import {Link, TextLink} from 'view/com/util/Link'
 import {SimpleViewHeader} from 'view/com/util/SimpleViewHeader'
@@ -61,8 +55,7 @@ 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 {useTheme} from '#/alf'
-import {atoms as a} from '#/alf'
+import {atoms as a, useTheme} from '#/alf'
 import {useDialogControl} from '#/components/Dialog'
 import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
 import {navigate, resetToTab} from '#/Navigation'
@@ -168,8 +161,6 @@ function SettingsAccountCard({
 type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'>
 export function SettingsScreen({}: Props) {
   const queryClient = useQueryClient()
-  const {colorMode, darkTheme} = useThemePrefs()
-  const {setColorMode, setDarkTheme} = useSetThemePrefs()
   const pal = usePalette('default')
   const {_} = useLingui()
   const setMinimalShellMode = useSetMinimalShellMode()
@@ -296,6 +287,10 @@ export function SettingsScreen({}: Props) {
     navigation.navigate('AccessibilitySettings')
   }, [navigation])
 
+  const onPressAppearanceSettings = React.useCallback(() => {
+    navigation.navigate('AppearanceSettings')
+  }, [navigation])
+
   const onPressBirthday = React.useCallback(() => {
     birthdayControl.open()
   }, [birthdayControl])
@@ -437,63 +432,6 @@ export function SettingsScreen({}: Props) {
         <View style={styles.spacer20} />
 
         <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          <Trans>Appearance</Trans>
-        </Text>
-        <View>
-          <View style={[styles.linkCard, pal.view, styles.selectableBtns]}>
-            <SelectableBtn
-              selected={colorMode === 'system'}
-              label={_(msg`System`)}
-              left
-              onSelect={() => setColorMode('system')}
-              accessibilityHint={_(msg`Sets color theme to system setting`)}
-            />
-            <SelectableBtn
-              selected={colorMode === 'light'}
-              label={_(msg`Light`)}
-              onSelect={() => setColorMode('light')}
-              accessibilityHint={_(msg`Sets color theme to light`)}
-            />
-            <SelectableBtn
-              selected={colorMode === 'dark'}
-              label={_(msg`Dark`)}
-              right
-              onSelect={() => setColorMode('dark')}
-              accessibilityHint={_(msg`Sets color theme to dark`)}
-            />
-          </View>
-        </View>
-
-        <View style={styles.spacer20} />
-
-        {colorMode !== 'light' && (
-          <>
-            <Text type="xl-bold" style={[pal.text, styles.heading]}>
-              <Trans>Dark Theme</Trans>
-            </Text>
-            <View>
-              <View style={[styles.linkCard, pal.view, styles.selectableBtns]}>
-                <SelectableBtn
-                  selected={!darkTheme || darkTheme === 'dim'}
-                  label={_(msg`Dim`)}
-                  left
-                  onSelect={() => setDarkTheme('dim')}
-                  accessibilityHint={_(msg`Sets dark theme to the dim theme`)}
-                />
-                <SelectableBtn
-                  selected={darkTheme === 'dark'}
-                  label={_(msg`Dark`)}
-                  right
-                  onSelect={() => setDarkTheme('dark')}
-                  accessibilityHint={_(msg`Sets dark theme to the dark theme`)}
-                />
-              </View>
-            </View>
-            <View style={styles.spacer20} />
-          </>
-        )}
-
-        <Text type="xl-bold" style={[pal.text, styles.heading]}>
           <Trans>Basics</Trans>
         </Text>
         <TouchableOpacity
@@ -520,6 +458,27 @@ export function SettingsScreen({}: Props) {
           </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,