This commit is contained in:
Eric Bailey
2024-09-15 12:39:48 -05:00
parent bf509eb6d5
commit 4a0f65c144
7 changed files with 134 additions and 39 deletions
+19
View File
@@ -1,5 +1,24 @@
import {useFonts as defaultUseFonts} from 'expo-font' import {useFonts as defaultUseFonts} from 'expo-font'
import {Device, device} from '#/storage'
export function getFontScale() {
const fontScale = device.get(['fontScale']) || 1
return fontScale
}
export function setFontScale(fontScale: Device['fontScale']) {
device.set(['fontScale'], fontScale)
}
export function getFontFamily() {
return device.get(['fontFamily']) || 'system'
}
export function setFontFamily(fontFamily: Device['fontFamily']) {
device.set(['fontFamily'], fontFamily)
}
export function useFonts() { export function useFonts() {
return defaultUseFonts({ return defaultUseFonts({
'Inter-Thin': require('../../assets/fonts/inter/Inter-Thin.otf'), 'Inter-Thin': require('../../assets/fonts/inter/Inter-Thin.otf'),
+57 -20
View File
@@ -2,10 +2,16 @@ import React from 'react'
import {useMediaQuery} from 'react-responsive' import {useMediaQuery} from 'react-responsive'
import {useGate} from '#/lib/statsig/statsig' import {useGate} from '#/lib/statsig/statsig'
import {
getFontFamily,
getFontScale,
setFontFamily as persistFontFamily,
setFontScale as persistFontScale,
} from '#/alf/fonts'
import {createThemes, defaultTheme} from '#/alf/themes' import {createThemes, defaultTheme} from '#/alf/themes'
import {Theme, ThemeName} from '#/alf/types' import {Theme, ThemeName} from '#/alf/types'
import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration' import {BLUE_HUE, GREEN_HUE, RED_HUE} from '#/alf/util/colorGeneration'
import * as fontScaling from '#/alf/util/fontScaling' import {Device} from '#/storage'
export {atoms} from '#/alf/atoms' export {atoms} from '#/alf/atoms'
export * from '#/alf/fonts' export * from '#/alf/fonts'
@@ -19,8 +25,12 @@ export type Alf = {
themeName: ThemeName themeName: ThemeName
theme: Theme theme: Theme
themes: ReturnType<typeof createThemes> themes: ReturnType<typeof createThemes>
fontScale: number fonts: {
setFontScale: (fontScale: number) => void scale: Exclude<Device['fontScale'], undefined>
family: Device['fontFamily']
setFontScale: (fontScale: Exclude<Device['fontScale'], undefined>) => void
setFontFamily: (fontFamily: Device['fontFamily']) => void
}
flags: { flags: {
neue: boolean neue: boolean
} }
@@ -39,8 +49,12 @@ export const Context = React.createContext<Alf>({
positive: GREEN_HUE, positive: GREEN_HUE,
}, },
}), }),
fontScale: fontScaling.get(), fonts: {
setFontScale: () => {}, scale: getFontScale(),
family: getFontFamily(),
setFontScale: () => {},
setFontFamily: () => {},
},
flags: { flags: {
neue: false, neue: false,
}, },
@@ -52,17 +66,33 @@ export function ThemeProvider({
}: React.PropsWithChildren<{theme: ThemeName}>) { }: React.PropsWithChildren<{theme: ThemeName}>) {
const gate = useGate() const gate = useGate()
const [neue] = React.useState(() => gate('typography_neue')) const [neue] = React.useState(() => gate('typography_neue'))
const [fontScale, setFontScale] = React.useState(() => { const [fontScale, setFontScale] = React.useState<Alf['fonts']['scale']>(
if (!neue) return 1 () => {
return fontScaling.get() if (!neue) return 1
}) return getFontScale()
const setFontScaleAndPersist = React.useCallback( },
(fontScale: number) => { )
const setFontScaleAndPersist = React.useCallback<
Alf['fonts']['setFontScale']
>(
fontScale => {
setFontScale(fontScale) setFontScale(fontScale)
fontScaling.set(fontScale) persistFontScale(fontScale)
}, },
[setFontScale], [setFontScale],
) )
const [fontFamily, setFontFamily] = React.useState<Alf['fonts']['family']>(
() => getFontFamily(),
)
const setFontFamilyAndPersist = React.useCallback<
Alf['fonts']['setFontFamily']
>(
fontFamily => {
setFontFamily(fontFamily)
persistFontFamily(fontFamily)
},
[setFontFamily],
)
const themes = React.useMemo(() => { const themes = React.useMemo(() => {
return createThemes({ return createThemes({
hues: { hues: {
@@ -80,13 +110,25 @@ export function ThemeProvider({
themes, themes,
themeName: themeName, themeName: themeName,
theme: themes[themeName], theme: themes[themeName],
fontScale, fonts: {
setFontScale: setFontScaleAndPersist, scale: fontScale,
family: fontFamily,
setFontScale: setFontScaleAndPersist,
setFontFamily: setFontFamilyAndPersist,
},
flags: { flags: {
neue, neue,
}, },
}), }),
[themeName, themes, fontScale, setFontScaleAndPersist, neue], [
themeName,
themes,
neue,
fontScale,
setFontScaleAndPersist,
fontFamily,
setFontFamilyAndPersist,
],
)}> )}>
{children} {children}
</Context.Provider> </Context.Provider>
@@ -97,11 +139,6 @@ export function useAlf() {
return React.useContext(Context) return React.useContext(Context)
} }
export function useFontScale() {
const {fontScale, setFontScale} = useAlf()
return {fontScale, setFontScale}
}
export function useTheme(theme?: ThemeName) { export function useTheme(theme?: ThemeName) {
const alf = useAlf() const alf = useAlf()
return React.useMemo(() => { return React.useMemo(() => {
+14 -5
View File
@@ -3,7 +3,7 @@ import {StyleProp, TextProps as RNTextProps, TextStyle} from 'react-native'
import {UITextView} from 'react-native-uitextview' import {UITextView} from 'react-native-uitextview'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
import {applyFonts, atoms, flatten, useAlf, useTheme, web} from '#/alf' import {Alf, applyFonts, atoms, flatten, useAlf, useTheme, web} from '#/alf'
export type TextProps = RNTextProps & { export type TextProps = RNTextProps & {
/** /**
@@ -36,7 +36,15 @@ export function leading<
*/ */
export function normalizeTextStyles( export function normalizeTextStyles(
styles: StyleProp<TextStyle>, styles: StyleProp<TextStyle>,
{fontScale, flags}: {fontScale: number; flags: {neue: boolean}}, {
fontScale,
fontFamily,
flags,
}: {
fontScale: number
fontFamily: Alf['fonts']['family']
flags: {neue: boolean}
},
) { ) {
const s = flatten(styles) const s = flatten(styles)
// should always be defined on these components // should always be defined on these components
@@ -50,7 +58,7 @@ export function normalizeTextStyles(
s.lineHeight = s.fontSize s.lineHeight = s.fontSize
} }
if (flags.neue) { if (flags.neue && fontFamily === 'theme') {
applyFonts(s) applyFonts(s)
} }
@@ -61,10 +69,11 @@ export function normalizeTextStyles(
* Our main text component. Use this most of the time. * Our main text component. Use this most of the time.
*/ */
export function Text({style, selectable, ...rest}: TextProps) { export function Text({style, selectable, ...rest}: TextProps) {
const {fontScale, flags} = useAlf() const {fonts, flags} = useAlf()
const t = useTheme() const t = useTheme()
const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, flatten(style)], { const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, flatten(style)], {
fontScale, fontScale: fonts.scale,
fontFamily: fonts.family,
flags, flags,
}) })
+40 -2
View File
@@ -10,11 +10,13 @@ import {useLingui} from '@lingui/react'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {useGate} from '#/lib/statsig/statsig'
import {s} from '#/lib/styles' import {s} from '#/lib/styles'
import {useSetThemePrefs, useThemePrefs} from '#/state/shell' import {useSetThemePrefs, useThemePrefs} from '#/state/shell'
import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader' import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {ScrollView} from '#/view/com/util/Views' import {ScrollView} from '#/view/com/util/Views'
import {atoms as a, native, useTheme} from '#/alf' import {atoms as a, native, useAlf, useTheme} from '#/alf'
import * as Toggle from '#/components/forms/Toggle'
import * as ToggleButton from '#/components/forms/ToggleButton' import * as ToggleButton from '#/components/forms/ToggleButton'
import {Moon_Stroke2_Corner0_Rounded as MoonIcon} from '#/components/icons/Moon' import {Moon_Stroke2_Corner0_Rounded as MoonIcon} from '#/components/icons/Moon'
import {Phone_Stroke2_Corner0_Rounded as PhoneIcon} from '#/components/icons/Phone' import {Phone_Stroke2_Corner0_Rounded as PhoneIcon} from '#/components/icons/Phone'
@@ -22,13 +24,21 @@ import {Text} from '#/components/Typography'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppearanceSettings'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppearanceSettings'>
export function AppearanceSettingsScreen({}: Props) { export function AppearanceSettingsScreen({}: Props) {
const {_} = useLingui()
const t = useTheme() const t = useTheme()
const {_} = useLingui()
const gate = useGate()
const [neue] = React.useState(() => gate('typography_neue'))
const {isTabletOrMobile} = useWebMediaQueries() const {isTabletOrMobile} = useWebMediaQueries()
const {fonts} = useAlf()
const {colorMode, darkTheme} = useThemePrefs() const {colorMode, darkTheme} = useThemePrefs()
const {setColorMode, setDarkTheme} = useSetThemePrefs() const {setColorMode, setDarkTheme} = useSetThemePrefs()
const [fontScale, setFontScale] = React.useState(() => fonts.scale !== 1)
const [fontFamily, setFontFamily] = React.useState(
() => fonts.family === 'theme',
)
const onChangeAppearance = useCallback( const onChangeAppearance = useCallback(
(keys: string[]) => { (keys: string[]) => {
const appearance = keys.find(key => key !== colorMode) as const appearance = keys.find(key => key !== colorMode) as
@@ -128,6 +138,34 @@ export function AppearanceSettingsScreen({}: Props) {
</Animated.View> </Animated.View>
)} )}
</View> </View>
{neue && (
<View style={[a.p_xl, a.gap_lg]}>
<Text>Neue options</Text>
<Toggle.Item
name="Font scale"
label="Font scale"
value={fontScale}
onChange={checked => {
setFontScale(checked)
fonts.setFontScale(checked ? 0.9375 : 1)
}}>
<Toggle.LabelText>Enable new font scale</Toggle.LabelText>
<Toggle.Switch />
</Toggle.Item>
<Toggle.Item
name="Font family"
label="Font family"
value={fontFamily}
onChange={checked => {
setFontFamily(checked)
fonts.setFontFamily(checked ? 'theme' : 'system')
}}>
<Toggle.LabelText>Use theme font</Toggle.LabelText>
<Toggle.Switch />
</Toggle.Item>
</View>
)}
</ScrollView> </ScrollView>
</View> </View>
</LayoutAnimationConfig> </LayoutAnimationConfig>
+2
View File
@@ -2,6 +2,8 @@ import {MMKV} from 'react-native-mmkv'
import {Device} from '#/storage/schema' import {Device} from '#/storage/schema'
export * from '#/storage/schema'
/** /**
* Generic storage class. DO NOT use this directly. Instead, use the exported * Generic storage class. DO NOT use this directly. Instead, use the exported
* storage instances below. * storage instances below.
+1
View File
@@ -3,5 +3,6 @@
*/ */
export type Device = { export type Device = {
fontScale: number | undefined fontScale: number | undefined
fontFamily: 'system' | 'theme'
lastNuxDialog: string | undefined lastNuxDialog: string | undefined
} }
+1 -12
View File
@@ -54,7 +54,7 @@ import * as Toast from 'view/com/util/Toast'
import {UserAvatar} from 'view/com/util/UserAvatar' import {UserAvatar} from 'view/com/util/UserAvatar'
import {ScrollView} from 'view/com/util/Views' import {ScrollView} from 'view/com/util/Views'
import {DeactivateAccountDialog} from '#/screens/Settings/components/DeactivateAccountDialog' import {DeactivateAccountDialog} from '#/screens/Settings/components/DeactivateAccountDialog'
import {atoms as a, useAlf, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings' import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
import {Email2FAToggle} from './Email2FAToggle' import {Email2FAToggle} from './Email2FAToggle'
@@ -133,7 +133,6 @@ function SettingsAccountCard({
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'>
export function SettingsScreen({}: Props) { export function SettingsScreen({}: Props) {
const {setFontScale} = useAlf()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
@@ -820,16 +819,6 @@ export function SettingsScreen({}: Props) {
</TouchableOpacity> </TouchableOpacity>
{__DEV__ ? ( {__DEV__ ? (
<> <>
<TouchableOpacity
style={[pal.view, styles.linkCardNoIcon]}
onPress={() => setFontScale(0.9375)}
accessibilityRole="button"
accessibilityLabel={_(msg`Set test font scale`)}
accessibilityHint={_(msg`Set test font scale`)}>
<Text type="lg" style={pal.text}>
<Trans>Enable neue font scale</Trans>
</Text>
</TouchableOpacity>
<TouchableOpacity <TouchableOpacity
style={[pal.view, styles.linkCardNoIcon]} style={[pal.view, styles.linkCardNoIcon]}
onPress={onPressStorybook} onPress={onPressStorybook}