Add fontScale, gate it, fix some computes

This commit is contained in:
Eric Bailey
2024-09-13 17:55:15 -05:00
parent 78a531f5ff
commit d5b62f21f5
8 changed files with 148 additions and 110 deletions
+38 -43
View File
@@ -107,51 +107,46 @@ function InnerApp() {
}, [_]) }, [_])
return ( return (
<Alf theme={theme}> <StatsigProvider key={currentAccount?.did}>
<ThemeProvider theme={theme}> <Alf theme={theme}>
<Splash isReady={isReady && hasCheckedReferrer}> <ThemeProvider theme={theme}>
<ActiveVideoProvider> <Splash isReady={isReady && hasCheckedReferrer}>
<RootSiblingParent> <ActiveVideoProvider>
<React.Fragment <RootSiblingParent>
// Resets the entire tree below when it changes:
key={currentAccount?.did}>
<QueryProvider currentDid={currentAccount?.did}> <QueryProvider currentDid={currentAccount?.did}>
<StatsigProvider> <MessagesProvider>
<MessagesProvider> {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
{/* LabelDefsProvider MUST come before ModerationOptsProvider */} <LabelDefsProvider>
<LabelDefsProvider> <ModerationOptsProvider>
<ModerationOptsProvider> <LoggedOutViewProvider>
<LoggedOutViewProvider> <SelectedFeedProvider>
<SelectedFeedProvider> <HiddenRepliesProvider>
<HiddenRepliesProvider> <UnreadNotifsProvider>
<UnreadNotifsProvider> <BackgroundNotificationPreferencesProvider>
<BackgroundNotificationPreferencesProvider> <MutedThreadsProvider>
<MutedThreadsProvider> <ProgressGuideProvider>
<ProgressGuideProvider> <GestureHandlerRootView style={s.h100pct}>
<GestureHandlerRootView <TestCtrls />
style={s.h100pct}> <Shell />
<TestCtrls /> <NuxDialogs />
<Shell /> </GestureHandlerRootView>
<NuxDialogs /> </ProgressGuideProvider>
</GestureHandlerRootView> </MutedThreadsProvider>
</ProgressGuideProvider> </BackgroundNotificationPreferencesProvider>
</MutedThreadsProvider> </UnreadNotifsProvider>
</BackgroundNotificationPreferencesProvider> </HiddenRepliesProvider>
</UnreadNotifsProvider> </SelectedFeedProvider>
</HiddenRepliesProvider> </LoggedOutViewProvider>
</SelectedFeedProvider> </ModerationOptsProvider>
</LoggedOutViewProvider> </LabelDefsProvider>
</ModerationOptsProvider> </MessagesProvider>
</LabelDefsProvider>
</MessagesProvider>
</StatsigProvider>
</QueryProvider> </QueryProvider>
</React.Fragment> </RootSiblingParent>
</RootSiblingParent> </ActiveVideoProvider>
</ActiveVideoProvider> </Splash>
</Splash> </ThemeProvider>
</ThemeProvider> </Alf>
</Alf> </StatsigProvider>
) )
} }
+36 -40
View File
@@ -92,48 +92,44 @@ function InnerApp() {
return ( return (
<KeyboardProvider enabled={false}> <KeyboardProvider enabled={false}>
<Alf theme={theme}> <StatsigProvider key={currentAccount?.did}>
<ThemeProvider theme={theme}> <Alf theme={theme}>
<RootSiblingParent> <ThemeProvider theme={theme}>
<ActiveVideoProvider> <RootSiblingParent>
<React.Fragment <ActiveVideoProvider>
// Resets the entire tree below when it changes:
key={currentAccount?.did}>
<QueryProvider currentDid={currentAccount?.did}> <QueryProvider currentDid={currentAccount?.did}>
<StatsigProvider> <MessagesProvider>
<MessagesProvider> {/* LabelDefsProvider MUST come before ModerationOptsProvider */}
{/* LabelDefsProvider MUST come before ModerationOptsProvider */} <LabelDefsProvider>
<LabelDefsProvider> <ModerationOptsProvider>
<ModerationOptsProvider> <LoggedOutViewProvider>
<LoggedOutViewProvider> <SelectedFeedProvider>
<SelectedFeedProvider> <HiddenRepliesProvider>
<HiddenRepliesProvider> <UnreadNotifsProvider>
<UnreadNotifsProvider> <BackgroundNotificationPreferencesProvider>
<BackgroundNotificationPreferencesProvider> <MutedThreadsProvider>
<MutedThreadsProvider> <SafeAreaProvider>
<SafeAreaProvider> <ProgressGuideProvider>
<ProgressGuideProvider> <Shell />
<Shell /> <NuxDialogs />
<NuxDialogs /> </ProgressGuideProvider>
</ProgressGuideProvider> </SafeAreaProvider>
</SafeAreaProvider> </MutedThreadsProvider>
</MutedThreadsProvider> </BackgroundNotificationPreferencesProvider>
</BackgroundNotificationPreferencesProvider> </UnreadNotifsProvider>
</UnreadNotifsProvider> </HiddenRepliesProvider>
</HiddenRepliesProvider> </SelectedFeedProvider>
</SelectedFeedProvider> </LoggedOutViewProvider>
</LoggedOutViewProvider> </ModerationOptsProvider>
</ModerationOptsProvider> </LabelDefsProvider>
</LabelDefsProvider> </MessagesProvider>
</MessagesProvider>
</StatsigProvider>
</QueryProvider> </QueryProvider>
</React.Fragment> <ToastContainer />
<ToastContainer /> </ActiveVideoProvider>
</ActiveVideoProvider> </RootSiblingParent>
</RootSiblingParent> </ThemeProvider>
</ThemeProvider> </Alf>
</Alf> </StatsigProvider>
</KeyboardProvider> </KeyboardProvider>
) )
} }
+49 -12
View File
@@ -1,9 +1,11 @@
import React from 'react' import React from 'react'
import {useMediaQuery} from 'react-responsive' import {useMediaQuery} from 'react-responsive'
import {useGate} from '#/lib/statsig/statsig'
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'
export {atoms} from '#/alf/atoms' export {atoms} from '#/alf/atoms'
export * as tokens from '#/alf/tokens' export * as tokens from '#/alf/tokens'
@@ -12,14 +14,21 @@ export * from '#/alf/util/flatten'
export * from '#/alf/util/platform' export * from '#/alf/util/platform'
export * from '#/alf/util/themeSelector' export * from '#/alf/util/themeSelector'
/* export type Alf = {
* Context
*/
export const Context = React.createContext<{
themeName: ThemeName themeName: ThemeName
theme: Theme theme: Theme
themes: ReturnType<typeof createThemes> themes: ReturnType<typeof createThemes>
}>({ fontScale: number
setFontScale: (fontScale: number) => void
flags: {
neue: boolean
}
}
/*
* Context
*/
export const Context = React.createContext<Alf>({
themeName: 'light', themeName: 'light',
theme: defaultTheme, theme: defaultTheme,
themes: createThemes({ themes: createThemes({
@@ -29,12 +38,27 @@ export const Context = React.createContext<{
positive: GREEN_HUE, positive: GREEN_HUE,
}, },
}), }),
fontScale: fontScaling.get(),
setFontScale: () => {},
flags: {
neue: false,
},
}) })
export function ThemeProvider({ export function ThemeProvider({
children, children,
theme: themeName, theme: themeName,
}: React.PropsWithChildren<{theme: ThemeName}>) { }: React.PropsWithChildren<{theme: ThemeName}>) {
const gate = useGate()
const [neue] = React.useState(() => gate('typography_neue'))
const [fontScale, setFontScale] = React.useState(() => fontScaling.get())
const setFontScaleAndPersist = React.useCallback(
(fontScale: number) => {
setFontScale(fontScale)
fontScaling.set(fontScale)
},
[setFontScale],
)
const themes = React.useMemo(() => { const themes = React.useMemo(() => {
return createThemes({ return createThemes({
hues: { hues: {
@@ -44,28 +68,41 @@ export function ThemeProvider({
}, },
}) })
}, []) }, [])
const theme = themes[themeName]
return ( return (
<Context.Provider <Context.Provider
value={React.useMemo( value={React.useMemo<Alf>(
() => ({ () => ({
themes, themes,
themeName: themeName, themeName: themeName,
theme: theme, theme: themes[themeName],
fontScale,
setFontScale: setFontScaleAndPersist,
flags: {
neue,
},
}), }),
[theme, themeName, themes], [themeName, themes, fontScale, setFontScaleAndPersist, neue],
)}> )}>
{children} {children}
</Context.Provider> </Context.Provider>
) )
} }
export function useAlf() {
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 ctx = React.useContext(Context) const alf = useAlf()
return React.useMemo(() => { return React.useMemo(() => {
return theme ? ctx.themes[theme] : ctx.theme return theme ? alf.themes[theme] : alf.theme
}, [theme, ctx]) }, [theme, alf])
} }
export function useBreakpoints() { export function useBreakpoints() {
+10
View File
@@ -0,0 +1,10 @@
import {device} from '#/storage'
export function set(fontScale: number) {
device.set(['fontScale'], fontScale)
}
export function get() {
const fontScale = device.get(['fontScale']) || 1
return fontScale
}
+2 -10
View File
@@ -7,7 +7,6 @@ import {
PressableProps, PressableProps,
StyleProp, StyleProp,
StyleSheet, StyleSheet,
Text,
TextProps, TextProps,
TextStyle, TextStyle,
View, View,
@@ -17,7 +16,7 @@ import {LinearGradient} from 'expo-linear-gradient'
import {android, atoms as a, flatten, select, tokens, useTheme} from '#/alf' import {android, atoms as a, flatten, select, tokens, useTheme} from '#/alf'
import {Props as SVGIconProps} from '#/components/icons/common' import {Props as SVGIconProps} from '#/components/icons/common'
import {normalizeTextStyles} from '#/components/Typography' import {Text} from '#/components/Typography'
export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'gradient' export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'gradient'
export type ButtonColor = export type ButtonColor =
@@ -635,14 +634,7 @@ export function ButtonText({children, style, ...rest}: ButtonTextProps) {
const textStyles = useSharedButtonTextStyles() const textStyles = useSharedButtonTextStyles()
return ( return (
<Text <Text {...rest} style={[a.font_bold, a.text_center, textStyles, style]}>
{...rest}
style={normalizeTextStyles([
a.font_bold,
a.text_center,
textStyles,
style,
])}>
{children} {children}
</Text> </Text>
) )
+11 -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 {atoms, flatten, useTheme, web} from '#/alf' import {atoms, flatten, useAlf, useTheme, web} from '#/alf'
export type TextProps = RNTextProps & { export type TextProps = RNTextProps & {
/** /**
@@ -34,14 +34,17 @@ export function leading<
* If the `lineHeight` value is > 2, we assume it's an absolute value and * If the `lineHeight` value is > 2, we assume it's an absolute value and
* returns it as-is. * returns it as-is.
*/ */
export function normalizeTextStyles(styles: StyleProp<TextStyle>) { export function normalizeTextStyles(
styles: StyleProp<TextStyle>,
{fontScale}: {fontScale: number},
) {
const s = flatten(styles) const s = flatten(styles)
// should always be defined on these components // should always be defined on these components
const fontSize = s.fontSize || atoms.text_md.fontSize s.fontSize = (s.fontSize || atoms.text_md.fontSize) * fontScale
if (s?.lineHeight) { if (s?.lineHeight) {
if (s.lineHeight !== 0 && s.lineHeight <= 2) { if (s.lineHeight !== 0 && s.lineHeight <= 2) {
s.lineHeight = Math.round(fontSize * s.lineHeight) s.lineHeight = Math.round(s.fontSize * s.lineHeight)
} }
} else if (!isNative) { } else if (!isNative) {
s.lineHeight = s.fontSize s.lineHeight = s.fontSize
@@ -54,8 +57,11 @@ export function normalizeTextStyles(styles: StyleProp<TextStyle>) {
* 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} = 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,
})
return <UITextView selectable={selectable} uiTextView style={s} {...rest} /> return <UITextView selectable={selectable} uiTextView style={s} {...rest} />
} }
+1
View File
@@ -1,5 +1,6 @@
export type Gate = export type Gate =
// Keep this alphabetic please. // Keep this alphabetic please.
| 'debug_show_feedcontext' | 'debug_show_feedcontext'
| 'typography_neue'
| 'suggested_feeds_interstitial' | 'suggested_feeds_interstitial'
| 'ten_million_dialog' | 'ten_million_dialog'
+1
View File
@@ -2,5 +2,6 @@
* Device data that's specific to the device and does not vary based account * Device data that's specific to the device and does not vary based account
*/ */
export type Device = { export type Device = {
fontScale: number | undefined
lastNuxDialog: string | undefined lastNuxDialog: string | undefined
} }