Merge remote-tracking branch 'upstream/main' into Improve-notification-localization

This commit is contained in:
Minseo Lee
2024-09-19 10:11:16 +09:00
56 changed files with 940 additions and 546 deletions
+36 -2
View File
@@ -55,6 +55,7 @@ module.exports = function (config) {
: undefined : undefined
const UPDATES_ENABLED = !!UPDATES_CHANNEL const UPDATES_ENABLED = !!UPDATES_CHANNEL
const USE_SENTRY = Boolean(process.env.SENTRY_AUTH_TOKEN)
const SENTRY_DIST = `${PLATFORM}.${VERSION}.${IS_TESTFLIGHT ? 'tf' : ''}${ const SENTRY_DIST = `${PLATFORM}.${VERSION}.${IS_TESTFLIGHT ? 'tf' : ''}${
IS_DEV ? 'dev' : '' IS_DEV ? 'dev' : ''
}` }`
@@ -186,7 +187,15 @@ module.exports = function (config) {
}, },
plugins: [ plugins: [
'expo-localization', 'expo-localization',
Boolean(process.env.SENTRY_AUTH_TOKEN) && 'sentry-expo', USE_SENTRY && [
'@sentry/react-native/expo',
{
organization: 'blueskyweb',
project: 'react-native',
release: VERSION,
dist: SENTRY_DIST,
},
],
[ [
'expo-build-properties', 'expo-build-properties',
{ {
@@ -221,6 +230,31 @@ module.exports = function (config) {
'./plugins/shareExtension/withShareExtensions.js', './plugins/shareExtension/withShareExtensions.js',
'./plugins/notificationsExtension/withNotificationsExtension.js', './plugins/notificationsExtension/withNotificationsExtension.js',
'./plugins/withAppDelegateReferrer.js', './plugins/withAppDelegateReferrer.js',
[
'expo-font',
{
fonts: [
// './assets/fonts/inter/Inter-Thin.otf',
// './assets/fonts/inter/Inter-ThinItalic.otf',
// './assets/fonts/inter/Inter-ExtraLight.otf',
// './assets/fonts/inter/Inter-ExtraLightItalic.otf',
// './assets/fonts/inter/Inter-Light.otf',
// './assets/fonts/inter/Inter-LightItalic.otf',
'./assets/fonts/inter/Inter-Regular.otf',
'./assets/fonts/inter/Inter-Italic.otf',
'./assets/fonts/inter/Inter-Medium.otf',
'./assets/fonts/inter/Inter-MediumItalic.otf',
'./assets/fonts/inter/Inter-SemiBold.otf',
'./assets/fonts/inter/Inter-SemiBoldItalic.otf',
'./assets/fonts/inter/Inter-Bold.otf',
'./assets/fonts/inter/Inter-BoldItalic.otf',
'./assets/fonts/inter/Inter-ExtraBold.otf',
'./assets/fonts/inter/Inter-ExtraBoldItalic.otf',
'./assets/fonts/inter/Inter-Black.otf',
'./assets/fonts/inter/Inter-BlackItalic.otf',
],
},
],
].filter(Boolean), ].filter(Boolean),
extra: { extra: {
eas: { eas: {
@@ -263,7 +297,7 @@ module.exports = function (config) {
* @see https://docs.expo.dev/guides/using-sentry/#app-configuration * @see https://docs.expo.dev/guides/using-sentry/#app-configuration
*/ */
{ {
file: 'sentry-expo/upload-sourcemaps', file: './postHooks/uploadSentrySourcemapsPostHook',
config: { config: {
organization: 'blueskyweb', organization: 'blueskyweb',
project: 'react-native', project: 'react-native',
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M9 5a1 1 0 0 1 1-1h12a1 1 0 1 1 0 2h-5v14a1 1 0 1 1-2 0V6h-5a1 1 0 0 1-1-1Zm-3.073 7v8a1 1 0 1 0 2 0v-8H12a1 1 0 1 0 0-2H6.971a1.015 1.015 0 0 0-.089 0H2a1 1 0 1 0 0 2h3.927Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 317 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3.65 17.247c-.242.832-.632 1.178-1.325 1.178-.814 0-1.325-.476-1.325-1.23 0-.216.06-.51.173-.831L4.586 7.07c.364-1.014.979-1.482 1.966-1.482 1.022 0 1.629.45 2.001 1.473l3.43 9.303c.121.337.165.571.165.831 0 .72-.546 1.23-1.308 1.23-.736 0-1.126-.338-1.36-1.152l-.658-1.975H4.309l-.658 1.95ZM6.5 8.152l-1.62 5.12h3.335l-1.654-5.12H6.5Zm13.005 8.688c-.52.988-1.68 1.568-2.84 1.568-1.768 0-3.11-1.144-3.11-2.815 0-1.69 1.299-2.668 3.62-2.807l2.34-.138v-.615c0-.867-.607-1.369-1.56-1.369-.771 0-1.239.251-1.802.979-.277.312-.597.468-1.004.468-.615 0-1.057-.399-1.057-.97 0-.2.043-.382.13-.572.433-1.109 1.923-1.793 3.845-1.793 2.383 0 3.933 1.23 3.933 3.1v5.293c0 .84-.511 1.273-1.23 1.273-.684 0-1.16-.38-1.213-1.126v-.476h-.052Zm-3.43-1.386c0 .693.572 1.126 1.42 1.126 1.11 0 2.02-.719 2.02-1.723v-.676l-1.959.121c-.944.07-1.48.494-1.48 1.152Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 986 B

+1 -1
View File
@@ -124,6 +124,7 @@
"expo-dev-client": "^4.0.14", "expo-dev-client": "^4.0.14",
"expo-device": "~6.0.2", "expo-device": "~6.0.2",
"expo-file-system": "^17.0.1", "expo-file-system": "^17.0.1",
"expo-font": "~12.0.10",
"expo-haptics": "^13.0.1", "expo-haptics": "^13.0.1",
"expo-image": "~1.12.9", "expo-image": "~1.12.9",
"expo-image-manipulator": "^12.0.5", "expo-image-manipulator": "^12.0.5",
@@ -200,7 +201,6 @@
"react-responsive": "^9.0.2", "react-responsive": "^9.0.2",
"react-textarea-autosize": "^8.5.3", "react-textarea-autosize": "^8.5.3",
"rn-fetch-blob": "^0.12.0", "rn-fetch-blob": "^0.12.0",
"sentry-expo": "~7.0.1",
"statsig-react-native-expo": "^4.6.1", "statsig-react-native-expo": "^4.6.1",
"tippy.js": "^6.3.7", "tippy.js": "^6.3.7",
"tlds": "^1.234.0", "tlds": "^1.234.0",
+36
View File
@@ -0,0 +1,36 @@
diff --git a/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js b/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
index 7e0b4cd..177454c 100644
--- a/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
+++ b/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
@@ -3,6 +3,8 @@ import { LogBox } from 'react-native';
* This is a workaround for using fetch on RN, this is a known issue in react-native and only generates a warning.
*/
export function ignoreRequireCycleLogs() {
- LogBox.ignoreLogs(['Require cycle:']);
+ try {
+ LogBox.ignoreLogs(['Require cycle:']);
+ } catch (e) {}
}
//# sourceMappingURL=ignorerequirecyclelogs.js.map
\ No newline at end of file
diff --git a/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js b/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js
index 0f244f2..ae7dfb3 100755
--- a/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js
+++ b/node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps.js
@@ -174,6 +174,7 @@ if (!outputDir) {
process.exit(1);
}
+const otherArgs = process.argv.slice(3);
const files = getAssetPathsSync(outputDir);
const groupedAssets = groupAssets(files);
@@ -195,7 +196,7 @@ for (const [assetGroupName, assets] of Object.entries(groupedAssets)) {
const isHermes = assets.find(asset => asset.endsWith('.hbc'));
const windowsCallback = process.platform === "win32" ? 'node ' : '';
- execSync(`${windowsCallback}${sentryCliBin} sourcemaps upload ${isHermes ? '--debug-id-reference' : ''} ${assets.join(' ')}`, {
+ execSync(`${windowsCallback}${sentryCliBin} sourcemaps upload ${isHermes ? '--debug-id-reference' : ''} ${assets.join(' ')} ${otherArgs.join(' ')}`, {
env: {
...process.env,
[SENTRY_PROJECT]: sentryProject,
-15
View File
@@ -1,15 +0,0 @@
diff --git a/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js b/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
index 7e0b4cd..177454c 100644
--- a/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
+++ b/node_modules/@sentry/react-native/dist/js/utils/ignorerequirecyclelogs.js
@@ -3,6 +3,8 @@ import { LogBox } from 'react-native';
* This is a workaround for using fetch on RN, this is a known issue in react-native and only generates a warning.
*/
export function ignoreRequireCycleLogs() {
- LogBox.ignoreLogs(['Require cycle:']);
+ try {
+ LogBox.ignoreLogs(['Require cycle:']);
+ } catch (e) {}
}
//# sourceMappingURL=ignorerequirecyclelogs.js.map
\ No newline at end of file
-25
View File
@@ -12,28 +12,3 @@ index bb74e80..0aa0202 100644
Map<String, Object> constants = new HashMap<>(3); Map<String, Object> constants = new HashMap<>(3);
constants.put(MODULES_CONSTANTS_KEY, new HashMap<>()); constants.put(MODULES_CONSTANTS_KEY, new HashMap<>());
diff --git a/node_modules/expo-modules-core/build/uuid/uuid.js b/node_modules/expo-modules-core/build/uuid/uuid.js
index 109d3fe..c421931 100644
--- a/node_modules/expo-modules-core/build/uuid/uuid.js
+++ b/node_modules/expo-modules-core/build/uuid/uuid.js
@@ -1,5 +1,7 @@
import bytesToUuid from './lib/bytesToUuid';
import { Uuidv5Namespace } from './uuid.types';
+import { ensureNativeModulesAreInstalled } from '../ensureNativeModulesAreInstalled';
+ensureNativeModulesAreInstalled();
const nativeUuidv4 = globalThis?.expo?.uuidv4;
const nativeUuidv5 = globalThis?.expo?.uuidv5;
function uuidv4() {
diff --git a/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift b/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift
index ee2268a..4851b67 100644
--- a/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift
+++ b/node_modules/expo-modules-core/ios/Core/SharedObjects/SharedObjectRegistry.swift
@@ -173,7 +173,7 @@ public final class SharedObjectRegistry {
}
internal func clear() {
- Self.lockQueue.async {
+ Self.lockQueue.sync {
self.pairs.removeAll()
}
}
@@ -0,0 +1,34 @@
const exec = require('child_process').execSync
const SENTRY_AUTH_TOKEN = process.env.SENTRY_AUTH_TOKEN
module.exports = ({config}) => {
if (!SENTRY_AUTH_TOKEN) {
console.log(
'SENTRY_AUTH_TOKEN environment variable must be set to upload sourcemaps. Skipping.',
)
return
}
const org = config.organization
const project = config.project
const release = config.release
const dist = config.dist
if (!org || !project || !release || !dist) {
console.log(
'"organization", "project", "release", and "dist" must be set in the hook config to upload sourcemaps. Skipping.',
)
return
}
try {
console.log('Uploading sourcemaps to Sentry...')
exec(
`node node_modules/@sentry/react-native/scripts/expo-upload-sourcemaps dist --url https://sentry.io/ -o ${org} -p ${project} -r ${release} -d ${dist}`,
)
console.log('Sourcemaps uploaded to Sentry.')
} catch (e) {
console.error('Error uploading sourcemaps to Sentry:', e)
}
}
+43 -45
View File
@@ -55,7 +55,7 @@ import {TestCtrls} from '#/view/com/testing/TestCtrls'
import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext' import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/VideoVolumeContext'
import * as Toast from '#/view/com/util/Toast' import * as Toast from '#/view/com/util/Toast'
import {Shell} from '#/view/shell' import {Shell} from '#/view/shell'
import {ThemeProvider as Alf} from '#/alf' import {ThemeProvider as Alf, useFonts} from '#/alf'
import {useColorModeTheme} from '#/alf/util/useColorModeTheme' import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {NuxDialogs} from '#/components/dialogs/nuxs' import {NuxDialogs} from '#/components/dialogs/nuxs'
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry' import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
@@ -106,62 +106,60 @@ function InnerApp() {
}, [_]) }, [_])
return ( return (
<Alf theme={theme}> <StatsigProvider
<ThemeProvider theme={theme}> // Resets the entire tree below when it changes:
<Splash isReady={isReady && hasCheckedReferrer}> key={currentAccount?.did}>
<RootSiblingParent> <Alf theme={theme}>
<VideoVolumeProvider> <ThemeProvider theme={theme}>
<React.Fragment <Splash isReady={isReady && hasCheckedReferrer}>
// Resets the entire tree below when it changes: <RootSiblingParent>
key={currentAccount?.did}> <VideoVolumeProvider>
<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> </VideoVolumeProvider>
</VideoVolumeProvider> </RootSiblingParent>
</RootSiblingParent> </Splash>
</Splash> </ThemeProvider>
</ThemeProvider> </Alf>
</Alf> </StatsigProvider>
) )
} }
function App() { function App() {
const [isReady, setReady] = useState(false) const [isReady, setReady] = useState(false)
const [loaded] = useFonts()
React.useEffect(() => { React.useEffect(() => {
initPersistedState().then(() => setReady(true)) initPersistedState().then(() => setReady(true))
}, []) }, [])
if (!isReady) { if (!isReady || !loaded) {
return null return null
} }
+43 -44
View File
@@ -46,7 +46,7 @@ import {Provider as VideoVolumeProvider} from '#/view/com/util/post-embeds/Video
import * as Toast from '#/view/com/util/Toast' import * as Toast from '#/view/com/util/Toast'
import {ToastContainer} from '#/view/com/util/Toast.web' import {ToastContainer} from '#/view/com/util/Toast.web'
import {Shell} from '#/view/shell/index' import {Shell} from '#/view/shell/index'
import {ThemeProvider as Alf} from '#/alf' import {ThemeProvider as Alf, useFonts} from '#/alf'
import {useColorModeTheme} from '#/alf/util/useColorModeTheme' import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {NuxDialogs} from '#/components/dialogs/nuxs' import {NuxDialogs} from '#/components/dialogs/nuxs'
import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry' import {useStarterPackEntry} from '#/components/hooks/useStarterPackEntry'
@@ -96,62 +96,61 @@ function InnerApp() {
return ( return (
<KeyboardProvider enabled={false}> <KeyboardProvider enabled={false}>
<Alf theme={theme}> <StatsigProvider
<ThemeProvider theme={theme}> // Resets the entire tree below when it changes:
<RootSiblingParent> key={currentAccount?.did}>
<VideoVolumeProvider> <Alf theme={theme}>
<ActiveVideoProvider> <ThemeProvider theme={theme}>
<React.Fragment <RootSiblingParent>
// Resets the entire tree below when it changes: <VideoVolumeProvider>
key={currentAccount?.did}> <ActiveVideoProvider>
<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> </VideoVolumeProvider>
</VideoVolumeProvider> </RootSiblingParent>
</RootSiblingParent> </ThemeProvider>
</ThemeProvider> </Alf>
</Alf> </StatsigProvider>
</KeyboardProvider> </KeyboardProvider>
) )
} }
function App() { function App() {
const [isReady, setReady] = useState(false) const [isReady, setReady] = useState(false)
const [loaded] = useFonts()
React.useEffect(() => { React.useEffect(() => {
initPersistedState().then(() => setReady(true)) initPersistedState().then(() => setReady(true))
}, []) }, [])
if (!isReady) { if (!isReady || !loaded) {
return null return null
} }
+11 -14
View File
@@ -225,43 +225,43 @@ export const atoms = {
}, },
text_2xs: { text_2xs: {
fontSize: tokens.fontSize._2xs, fontSize: tokens.fontSize._2xs,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
text_xs: { text_xs: {
fontSize: tokens.fontSize.xs, fontSize: tokens.fontSize.xs,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
text_sm: { text_sm: {
fontSize: tokens.fontSize.sm, fontSize: tokens.fontSize.sm,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
text_md: { text_md: {
fontSize: tokens.fontSize.md, fontSize: tokens.fontSize.md,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
text_lg: { text_lg: {
fontSize: tokens.fontSize.lg, fontSize: tokens.fontSize.lg,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
text_xl: { text_xl: {
fontSize: tokens.fontSize.xl, fontSize: tokens.fontSize.xl,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
text_2xl: { text_2xl: {
fontSize: tokens.fontSize._2xl, fontSize: tokens.fontSize._2xl,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
text_3xl: { text_3xl: {
fontSize: tokens.fontSize._3xl, fontSize: tokens.fontSize._3xl,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
text_4xl: { text_4xl: {
fontSize: tokens.fontSize._4xl, fontSize: tokens.fontSize._4xl,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
text_5xl: { text_5xl: {
fontSize: tokens.fontSize._5xl, fontSize: tokens.fontSize._5xl,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
}, },
leading_tight: { leading_tight: {
lineHeight: 1.15, lineHeight: 1.15,
@@ -273,10 +273,7 @@ export const atoms = {
lineHeight: 1.5, lineHeight: 1.5,
}, },
tracking_normal: { tracking_normal: {
letterSpacing: 0, letterSpacing: tokens.TRACKING,
},
tracking_wide: {
letterSpacing: 0.25,
}, },
font_normal: { font_normal: {
fontWeight: tokens.fontWeight.normal, fontWeight: tokens.fontWeight.normal,
+111
View File
@@ -0,0 +1,111 @@
import {useFonts as defaultUseFonts} from 'expo-font'
import {isNative, isWeb} from '#/platform/detection'
import {Device, device} from '#/storage'
const FAMILIES = `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif`
const factor = 0.0625 // 1 - (15/16)
const fontScaleMultipliers: Record<Device['fontScale'], number> = {
'-2': 1 - factor * 3,
'-1': 1 - factor * 2,
'0': 1 - factor * 1, // default
'1': 1,
'2': 1 + factor * 1,
}
export function computeFontScaleMultiplier(scale: Device['fontScale']) {
return fontScaleMultipliers[scale]
}
export function getFontScale() {
return device.get(['fontScale']) ?? '0'
}
export function setFontScale(fontScale: Device['fontScale']) {
device.set(['fontScale'], fontScale)
}
export function getFontFamily() {
return device.get(['fontFamily']) || 'theme'
}
export function setFontFamily(fontFamily: Device['fontFamily']) {
device.set(['fontFamily'], fontFamily)
}
/*
* Unused fonts are commented out, but the files are there if we need them.
*/
export function useFonts() {
/**
* For native, the `expo-font` config plugin embeds the fonts in the
* application binary. But `expo-font` isn't supported on web, so we fall
* back to async loading here.
*/
if (isNative) return [true, null]
return defaultUseFonts({
// 'Inter-Thin': require('../../assets/fonts/inter/Inter-Thin.otf'),
// 'Inter-ThinItalic': require('../../assets/fonts/inter/Inter-ThinItalic.otf'),
// 'Inter-ExtraLight': require('../../assets/fonts/inter/Inter-ExtraLight.otf'),
// 'Inter-ExtraLightItalic': require('../../assets/fonts/inter/Inter-ExtraLightItalic.otf'),
// 'Inter-Light': require('../../assets/fonts/inter/Inter-Light.otf'),
// 'Inter-LightItalic': require('../../assets/fonts/inter/Inter-LightItalic.otf'),
'Inter-Regular': require('../../assets/fonts/inter/Inter-Regular.otf'),
'Inter-Italic': require('../../assets/fonts/inter/Inter-Italic.otf'),
'Inter-Medium': require('../../assets/fonts/inter/Inter-Medium.otf'),
'Inter-MediumItalic': require('../../assets/fonts/inter/Inter-MediumItalic.otf'),
'Inter-SemiBold': require('../../assets/fonts/inter/Inter-SemiBold.otf'),
'Inter-SemiBoldItalic': require('../../assets/fonts/inter/Inter-SemiBoldItalic.otf'),
'Inter-Bold': require('../../assets/fonts/inter/Inter-Bold.otf'),
'Inter-BoldItalic': require('../../assets/fonts/inter/Inter-BoldItalic.otf'),
'Inter-ExtraBold': require('../../assets/fonts/inter/Inter-ExtraBold.otf'),
'Inter-ExtraBoldItalic': require('../../assets/fonts/inter/Inter-ExtraBoldItalic.otf'),
'Inter-Black': require('../../assets/fonts/inter/Inter-Black.otf'),
'Inter-BlackItalic': require('../../assets/fonts/inter/Inter-BlackItalic.otf'),
})
}
/*
* Unused fonts are commented out, but the files are there if we need them.
*/
export function applyFonts(
style: Record<string, any>,
fontFamily: 'system' | 'theme',
) {
if (fontFamily === 'theme') {
style.fontFamily =
{
// '100': 'Inter-Thin',
// '200': 'Inter-ExtraLight',
// '300': 'Inter-Light',
'100': 'Inter-Regular',
'200': 'Inter-Regular',
'300': 'Inter-Regular',
'400': 'Inter-Regular',
'500': 'Inter-Medium',
'600': 'Inter-SemiBold',
'700': 'Inter-Bold',
'800': 'Inter-ExtraBold',
'900': 'Inter-Black',
}[style.fontWeight as string] || 'Inter-Regular'
if (style.fontStyle === 'italic') {
if (style.fontFamily === 'Inter-Regular') {
style.fontFamily = 'Inter-Italic'
} else {
style.fontFamily += 'Italic'
}
}
// fallback families only supported on web
if (isWeb) {
style.fontFamily += `, ${FAMILIES}`
}
} else {
// fallback families only supported on web
if (isWeb) {
style.fontFamily = style.fontFamily || FAMILIES
}
}
}
+89 -12
View File
@@ -1,25 +1,47 @@
import React from 'react' import React from 'react'
import {useMediaQuery} from 'react-responsive' import {useMediaQuery} from 'react-responsive'
import {
computeFontScaleMultiplier,
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 {Device} from '#/storage'
export {atoms} from '#/alf/atoms' export {atoms} from '#/alf/atoms'
export * from '#/alf/fonts'
export * as tokens from '#/alf/tokens' export * as tokens from '#/alf/tokens'
export * from '#/alf/types' export * from '#/alf/types'
export * from '#/alf/util/flatten' 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>
}>({ fonts: {
scale: Exclude<Device['fontScale'], undefined>
scaleMultiplier: number
family: Device['fontFamily']
setFontScale: (fontScale: Exclude<Device['fontScale'], undefined>) => void
setFontFamily: (fontFamily: Device['fontFamily']) => void
}
/**
* Feature flags or other gated options
*/
flags: {}
}
/*
* Context
*/
export const Context = React.createContext<Alf>({
themeName: 'light', themeName: 'light',
theme: defaultTheme, theme: defaultTheme,
themes: createThemes({ themes: createThemes({
@@ -29,12 +51,48 @@ export const Context = React.createContext<{
positive: GREEN_HUE, positive: GREEN_HUE,
}, },
}), }),
fonts: {
scale: getFontScale(),
scaleMultiplier: computeFontScaleMultiplier(getFontScale()),
family: getFontFamily(),
setFontScale: () => {},
setFontFamily: () => {},
},
flags: {},
}) })
export function ThemeProvider({ export function ThemeProvider({
children, children,
theme: themeName, theme: themeName,
}: React.PropsWithChildren<{theme: ThemeName}>) { }: React.PropsWithChildren<{theme: ThemeName}>) {
const [fontScale, setFontScale] = React.useState<Alf['fonts']['scale']>(() =>
getFontScale(),
)
const [fontScaleMultiplier, setFontScaleMultiplier] = React.useState(() =>
computeFontScaleMultiplier(fontScale),
)
const setFontScaleAndPersist = React.useCallback<
Alf['fonts']['setFontScale']
>(
fontScale => {
setFontScale(fontScale)
persistFontScale(fontScale)
setFontScaleMultiplier(computeFontScaleMultiplier(fontScale))
},
[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: {
@@ -44,28 +102,47 @@ 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],
fonts: {
scale: fontScale,
scaleMultiplier: fontScaleMultiplier,
family: fontFamily,
setFontScale: setFontScaleAndPersist,
setFontFamily: setFontFamilyAndPersist,
},
flags: {},
}), }),
[theme, themeName, themes], [
themeName,
themes,
fontScale,
setFontScaleAndPersist,
fontFamily,
setFontFamilyAndPersist,
fontScaleMultiplier,
],
)}> )}>
{children} {children}
</Context.Provider> </Context.Provider>
) )
} }
export function useAlf() {
return React.useContext(Context)
}
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() {
+4
View File
@@ -1,3 +1,7 @@
import {Platform} from 'react-native'
export const TRACKING = Platform.OS === 'android' ? 0.1 : 0
export const color = { export const color = {
temp_purple: 'rgb(105 0 255)', temp_purple: 'rgb(105 0 255)',
temp_purple_dark: 'rgb(83 0 202)', temp_purple_dark: 'rgb(83 0 202)',
+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>
) )
+1
View File
@@ -37,6 +37,7 @@ import {Portal} from '#/components/Portal'
export {useDialogContext, useDialogControl} from '#/components/Dialog/context' export {useDialogContext, useDialogControl} from '#/components/Dialog/context'
export * from '#/components/Dialog/types' export * from '#/components/Dialog/types'
export * from '#/components/Dialog/utils'
// @ts-ignore // @ts-ignore
export const Input = createInput(BottomSheetTextInput) export const Input = createInput(BottomSheetTextInput)
+1
View File
@@ -27,6 +27,7 @@ import {Portal} from '#/components/Portal'
export {useDialogContext, useDialogControl} from '#/components/Dialog/context' export {useDialogContext, useDialogControl} from '#/components/Dialog/context'
export * from '#/components/Dialog/types' export * from '#/components/Dialog/types'
export * from '#/components/Dialog/utils'
export {Input} from '#/components/forms/TextField' export {Input} from '#/components/forms/TextField'
const stopPropagation = (e: any) => e.stopPropagation() const stopPropagation = (e: any) => e.stopPropagation()
+18
View File
@@ -0,0 +1,18 @@
import React from 'react'
import {DialogControlProps} from '#/components/Dialog/types'
export function useAutoOpen(control: DialogControlProps, showTimeout?: number) {
React.useEffect(() => {
if (showTimeout) {
const timeout = setTimeout(() => {
control.open()
}, showTimeout)
return () => {
clearTimeout(timeout)
}
} else {
control.open()
}
}, [control, showTimeout])
}
+21 -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 {Alf, applyFonts, atoms, flatten, useAlf, useTheme, web} from '#/alf'
export type TextProps = RNTextProps & { export type TextProps = RNTextProps & {
/** /**
@@ -34,19 +34,30 @@ 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,
fontFamily,
}: {
fontScale: number
fontFamily: Alf['fonts']['family']
} & Pick<Alf, 'flags'>,
) {
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
} }
applyFonts(s, fontFamily)
return s return s
} }
@@ -54,8 +65,13 @@ 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 {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: fonts.scaleMultiplier,
fontFamily: fonts.family,
flags,
})
return <UITextView selectable={selectable} uiTextView style={s} {...rest} /> return <UITextView selectable={selectable} uiTextView style={s} {...rest} />
} }
@@ -0,0 +1,119 @@
import React from 'react'
import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {AppearanceToggleButtonGroup} from '#/screens/Settings/AppearanceSettings'
import {atoms as a, useAlf, useTheme} from '#/alf'
import * as Dialog from '#/components/Dialog'
import {useNuxDialogContext} from '#/components/dialogs/nuxs'
import {Divider} from '#/components/Divider'
import {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/TextSize'
import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase'
import {Text} from '#/components/Typography'
export function NeueTypography() {
const t = useTheme()
const {_} = useLingui()
const nuxDialogs = useNuxDialogContext()
const control = Dialog.useDialogControl()
const {fonts} = useAlf()
Dialog.useAutoOpen(control, 3e3)
const onClose = React.useCallback(() => {
nuxDialogs.dismissActiveNux()
}, [nuxDialogs])
const onChangeFontFamily = React.useCallback(
(values: string[]) => {
const next = values[0] === 'system' ? 'system' : 'theme'
fonts.setFontFamily(next)
},
[fonts],
)
const onChangeFontScale = React.useCallback(
(values: string[]) => {
const next = values[0] || ('0' as any)
fonts.setFontScale(next)
},
[fonts],
)
return (
<Dialog.Outer control={control} onClose={onClose}>
<Dialog.Handle />
<Dialog.ScrollableInner label={_(msg`Introducing new font settings`)}>
<View style={[a.gap_xl]}>
<View style={[a.gap_md]}>
<Text style={[a.text_3xl, {fontWeight: '900'}]}>
<Trans>Introducing new font settings </Trans>
</Text>
<Text style={[a.text_lg, a.leading_snug]}>
<Trans>
To the ensure the best possible experience, we're introducing a
new theme font, along with adjustable font sizing settings.
</Trans>
</Text>
<Text
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
<Trans>
Defaults are shown below. You can edit these in your Appearance
Settings later.
</Trans>
</Text>
</View>
<Divider />
<View style={[a.gap_lg]}>
<AppearanceToggleButtonGroup
title={_(msg`Font`)}
description={_(
msg`For the best experience, we recommend using the theme font.`,
)}
icon={Aa}
items={[
{
label: _(msg`System`),
name: 'system',
},
{
label: _(msg`Theme`),
name: 'theme',
},
]}
values={[fonts.family]}
onChange={onChangeFontFamily}
/>
<AppearanceToggleButtonGroup
title={_(msg`Font size`)}
icon={TextSize}
items={[
{
label: _(msg`Smaller`),
name: '-1',
},
{
label: _(msg`Default`),
name: '0',
},
{
label: _(msg`Larger`),
name: '1',
},
]}
values={[fonts.scale]}
onChange={onChangeFontScale}
/>
</View>
</View>
<Dialog.Close />
</Dialog.ScrollableInner>
</Dialog.Outer>
)
}
+71 -9
View File
@@ -1,4 +1,5 @@
import React from 'react' import React from 'react'
import {AppBskyActorDefs} from '@atproto/api'
import {useGate} from '#/lib/statsig/statsig' import {useGate} from '#/lib/statsig/statsig'
import {logger} from '#/logger' import {logger} from '#/logger'
@@ -8,9 +9,16 @@ import {
useRemoveNuxsMutation, useRemoveNuxsMutation,
useUpsertNuxMutation, useUpsertNuxMutation,
} from '#/state/queries/nuxs' } from '#/state/queries/nuxs'
import {useSession} from '#/state/session' import {
usePreferencesQuery,
UsePreferencesQueryResponse,
} from '#/state/queries/preferences'
import {useProfileQuery} from '#/state/queries/profile'
import {SessionAccount, useSession} from '#/state/session'
import {useOnboardingState} from '#/state/shell' import {useOnboardingState} from '#/state/shell'
import {NeueTypography} from '#/components/dialogs/nuxs/NeueTypography'
import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing' import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing'
// NUXs
import {TenMillion} from '#/components/dialogs/nuxs/TenMillion' import {TenMillion} from '#/components/dialogs/nuxs/TenMillion'
import {IS_DEV} from '#/env' import {IS_DEV} from '#/env'
@@ -21,11 +29,27 @@ type Context = {
const queuedNuxs: { const queuedNuxs: {
id: Nux id: Nux
enabled?: (props: {gate: ReturnType<typeof useGate>}) => boolean enabled?: (props: {
gate: ReturnType<typeof useGate>
currentAccount: SessionAccount
currentProfile: AppBskyActorDefs.ProfileViewDetailed
preferences: UsePreferencesQueryResponse
}) => boolean
}[] = [ }[] = [
{ {
id: Nux.TenMillionDialog, id: Nux.TenMillionDialog,
}, },
{
id: Nux.NeueTypography,
enabled(props) {
if (props.currentProfile.createdAt) {
if (new Date(props.currentProfile.createdAt) < new Date('2024-09-25')) {
return true
}
}
return false
},
},
] ]
const Context = React.createContext<Context>({ const Context = React.createContext<Context>({
@@ -38,12 +62,31 @@ export function useNuxDialogContext() {
} }
export function NuxDialogs() { export function NuxDialogs() {
const {hasSession} = useSession() const {currentAccount} = useSession()
const onboardingState = useOnboardingState() const {data: preferences} = usePreferencesQuery()
return hasSession && !onboardingState.isActive ? <Inner /> : null const {data: profile} = useProfileQuery({did: currentAccount?.did})
const onboardingActive = useOnboardingState().isActive
const isLoading =
!currentAccount || !preferences || !profile || onboardingActive
return !isLoading ? (
<Inner
currentAccount={currentAccount}
currentProfile={profile}
preferences={preferences}
/>
) : null
} }
function Inner() { function Inner({
currentAccount,
currentProfile,
preferences,
}: {
currentAccount: SessionAccount
currentProfile: AppBskyActorDefs.ProfileViewDetailed
preferences: UsePreferencesQueryResponse
}) {
const gate = useGate() const gate = useGate()
const {nuxs} = useNuxs() const {nuxs} = useNuxs()
const [snoozed, setSnoozed] = React.useState(() => { const [snoozed, setSnoozed] = React.useState(() => {
@@ -80,10 +123,19 @@ function Inner() {
const nux = nuxs.find(nux => nux.id === id) const nux = nuxs.find(nux => nux.id === id)
// check if completed first // check if completed first
if (nux && nux.completed) continue if (nux && nux.completed) {
continue
}
// then check gate (track exposure) // then check gate (track exposure)
if (enabled && !enabled({gate})) continue if (
enabled &&
!enabled({gate, currentAccount, currentProfile, preferences})
) {
continue
}
logger.debug(`NUX dialogs: activating '${id}' NUX`)
// we have a winner // we have a winner
setActiveNux(id) setActiveNux(id)
@@ -104,7 +156,16 @@ function Inner() {
break break
} }
}, [nuxs, snoozed, snoozeNuxDialog, upsertNux, gate]) }, [
nuxs,
snoozed,
snoozeNuxDialog,
upsertNux,
gate,
currentAccount,
currentProfile,
preferences,
])
const ctx = React.useMemo(() => { const ctx = React.useMemo(() => {
return { return {
@@ -116,6 +177,7 @@ function Inner() {
return ( return (
<Context.Provider value={ctx}> <Context.Provider value={ctx}>
{activeNux === Nux.TenMillionDialog && <TenMillion />} {activeNux === Nux.TenMillionDialog && <TenMillion />}
{activeNux === Nux.NeueTypography && <NeueTypography />}
</Context.Provider> </Context.Provider>
) )
} }
+5
View File
@@ -0,0 +1,5 @@
import {createSinglePathSVG} from './TEMPLATE'
export const TextSize_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M9 5a1 1 0 0 1 1-1h12a1 1 0 1 1 0 2h-5v14a1 1 0 1 1-2 0V6h-5a1 1 0 0 1-1-1Zm-3.073 7v8a1 1 0 1 0 2 0v-8H12a1 1 0 1 0 0-2H6.971a1.015 1.015 0 0 0-.089 0H2a1 1 0 1 0 0 2h3.927Z',
})
+5
View File
@@ -0,0 +1,5 @@
import {createSinglePathSVG} from './TEMPLATE'
export const TitleCase_Stroke2_Corner0_Rounded = createSinglePathSVG({
path: 'M3.65 17.247c-.242.832-.632 1.178-1.325 1.178-.814 0-1.325-.476-1.325-1.23 0-.216.06-.51.173-.831L4.586 7.07c.364-1.014.979-1.482 1.966-1.482 1.022 0 1.629.45 2.001 1.473l3.43 9.303c.121.337.165.571.165.831 0 .72-.546 1.23-1.308 1.23-.736 0-1.126-.338-1.36-1.152l-.658-1.975H4.309l-.658 1.95ZM6.5 8.152l-1.62 5.12h3.335l-1.654-5.12H6.5Zm13.005 8.688c-.52.988-1.68 1.568-2.84 1.568-1.768 0-3.11-1.144-3.11-2.815 0-1.69 1.299-2.668 3.62-2.807l2.34-.138v-.615c0-.867-.607-1.369-1.56-1.369-.771 0-1.239.251-1.802.979-.277.312-.597.468-1.004.468-.615 0-1.057-.399-1.057-.97 0-.2.043-.382.13-.572.433-1.109 1.923-1.793 3.845-1.793 2.383 0 3.933 1.23 3.933 3.1v5.293c0 .84-.511 1.273-1.23 1.273-.684 0-1.16-.38-1.213-1.126v-.476h-.052Zm-3.43-1.386c0 .693.572 1.126 1.42 1.126 1.11 0 2.02-.719 2.02-1.723v-.676l-1.959.121c-.944.07-1.48.494-1.48 1.152Z',
})
+4 -4
View File
@@ -2,12 +2,12 @@ import React from 'react'
import {AppState, AppStateStatus} from 'react-native' import {AppState, AppStateStatus} from 'react-native'
import AsyncStorage from '@react-native-async-storage/async-storage' import AsyncStorage from '@react-native-async-storage/async-storage'
import {createClient, SegmentClient} from '@segment/analytics-react-native' import {createClient, SegmentClient} from '@segment/analytics-react-native'
import * as Sentry from '@sentry/react-native'
import {sha256} from 'js-sha256' import {sha256} from 'js-sha256'
import {Native} from 'sentry-expo'
import {useSession, SessionAccount} from '#/state/session'
import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
import {logger} from '#/logger' import {logger} from '#/logger'
import {SessionAccount, useSession} from '#/state/session'
import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
type AppInfo = { type AppInfo = {
build?: string | undefined build?: string | undefined
@@ -72,7 +72,7 @@ export function init(account: SessionAccount | undefined) {
if (account.did) { if (account.did) {
const did_hashed = sha256(account.did) const did_hashed = sha256(account.did)
client.identify(did_hashed, {did_hashed}) client.identify(did_hashed, {did_hashed})
Native.setUser({id: did_hashed}) Sentry.setUser({id: did_hashed})
logger.debug('Ping w/hash') logger.debug('Ping w/hash')
} else { } else {
logger.debug('Ping w/o hash') logger.debug('Ping w/o hash')
+4 -4
View File
@@ -1,11 +1,11 @@
import React from 'react' import React from 'react'
import {createClient} from '@segment/analytics-react' import {createClient} from '@segment/analytics-react'
import * as Sentry from '@sentry/react-native'
import {sha256} from 'js-sha256' import {sha256} from 'js-sha256'
import {Browser} from 'sentry-expo'
import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
import {useSession, SessionAccount} from '#/state/session'
import {logger} from '#/logger' import {logger} from '#/logger'
import {SessionAccount, useSession} from '#/state/session'
import {ScreenPropertiesMap, TrackPropertiesMap} from './types'
type SegmentClient = ReturnType<typeof createClient> type SegmentClient = ReturnType<typeof createClient>
@@ -70,7 +70,7 @@ export function init(account: SessionAccount | undefined) {
if (account.did) { if (account.did) {
const did_hashed = sha256(account.did) const did_hashed = sha256(account.did)
client.identify(did_hashed, {did_hashed}) client.identify(did_hashed, {did_hashed})
Browser.setUser({id: did_hashed}) Sentry.setUser({id: did_hashed})
logger.debug('Ping w/hash') logger.debug('Ping w/hash')
} else { } else {
logger.debug('Ping w/o hash') logger.debug('Ping w/o hash')
+2 -2
View File
@@ -5,7 +5,7 @@
import {Platform} from 'react-native' import {Platform} from 'react-native'
import {nativeApplicationVersion, nativeBuildVersion} from 'expo-application' import {nativeApplicationVersion, nativeBuildVersion} from 'expo-application'
import {init} from 'sentry-expo' import {init} from '@sentry/react-native'
import {BUILD_ENV, IS_DEV, IS_TESTFLIGHT} from 'lib/app-info' import {BUILD_ENV, IS_DEV, IS_TESTFLIGHT} from 'lib/app-info'
@@ -30,10 +30,10 @@ const dist = `${Platform.OS}.${nativeBuildVersion}.${
}${IS_DEV ? 'dev' : ''}` }${IS_DEV ? 'dev' : ''}`
init({ init({
enabled: !__DEV__,
autoSessionTracking: false, autoSessionTracking: false,
dsn: 'https://05bc3789bf994b81bd7ce20c86ccd3ae@o4505071687041024.ingest.sentry.io/4505071690514432', dsn: 'https://05bc3789bf994b81bd7ce20c86ccd3ae@o4505071687041024.ingest.sentry.io/4505071690514432',
debug: false, // If `true`, Sentry will try to print out useful debugging information if something goes wrong with sending the event. Set it to `false` in production debug: false, // If `true`, Sentry will try to print out useful debugging information if something goes wrong with sending the event. Set it to `false` in production
enableInExpoDevelopment: false, // enable this to test in dev
environment: BUILD_ENV ?? 'development', environment: BUILD_ENV ?? 'development',
dist, dist,
release, release,
+3 -3
View File
@@ -79,13 +79,13 @@ export const s = StyleSheet.create({
// font weights // font weights
fw600: {fontWeight: '600'}, fw600: {fontWeight: '600'},
bold: {fontWeight: 'bold'}, bold: {fontWeight: '700'},
fw500: {fontWeight: '500'}, fw500: {fontWeight: '500'},
semiBold: {fontWeight: '500'}, semiBold: {fontWeight: '500'},
fw400: {fontWeight: '400'}, fw400: {fontWeight: '400'},
normal: {fontWeight: '400'}, normal: {fontWeight: '400'},
fw300: {fontWeight: '300'}, fw300: {fontWeight: '400'},
light: {fontWeight: '300'}, light: {fontWeight: '400'},
fw200: {fontWeight: '200'}, fw200: {fontWeight: '200'},
// text decoration // text decoration
+45 -44
View File
@@ -1,5 +1,6 @@
import {Platform} from 'react-native' import {Platform} from 'react-native'
import {tokens} from '#/alf'
import {darkPalette, dimPalette, lightPalette} from '#/alf/themes' import {darkPalette, dimPalette, lightPalette} from '#/alf/themes'
import {colors} from './styles' import {colors} from './styles'
import type {Theme} from './ThemeContext' import type {Theme} from './ThemeContext'
@@ -88,163 +89,163 @@ export const defaultTheme: Theme = {
typography: { typography: {
'2xl-thin': { '2xl-thin': {
fontSize: 18, fontSize: 18,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '300', fontWeight: '400',
}, },
'2xl': { '2xl': {
fontSize: 18, fontSize: 18,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '400', fontWeight: '400',
}, },
'2xl-medium': { '2xl-medium': {
fontSize: 18, fontSize: 18,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '500', fontWeight: '500',
}, },
'2xl-bold': { '2xl-bold': {
fontSize: 18, fontSize: 18,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '700', fontWeight: '700',
}, },
'2xl-heavy': { '2xl-heavy': {
fontSize: 18, fontSize: 18,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '800', fontWeight: '800',
}, },
'xl-thin': { 'xl-thin': {
fontSize: 17, fontSize: 17,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '300', fontWeight: '400',
}, },
xl: { xl: {
fontSize: 17, fontSize: 17,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '400', fontWeight: '400',
}, },
'xl-medium': { 'xl-medium': {
fontSize: 17, fontSize: 17,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '500', fontWeight: '500',
}, },
'xl-bold': { 'xl-bold': {
fontSize: 17, fontSize: 17,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '700', fontWeight: '700',
}, },
'xl-heavy': { 'xl-heavy': {
fontSize: 17, fontSize: 17,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '800', fontWeight: '800',
}, },
'lg-thin': { 'lg-thin': {
fontSize: 16, fontSize: 16,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '300', fontWeight: '400',
}, },
lg: { lg: {
fontSize: 16, fontSize: 16,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '400', fontWeight: '400',
}, },
'lg-medium': { 'lg-medium': {
fontSize: 16, fontSize: 16,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '500', fontWeight: '500',
}, },
'lg-bold': { 'lg-bold': {
fontSize: 16, fontSize: 16,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '700', fontWeight: '700',
}, },
'lg-heavy': { 'lg-heavy': {
fontSize: 16, fontSize: 16,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '800', fontWeight: '800',
}, },
'md-thin': { 'md-thin': {
fontSize: 15, fontSize: 15,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '300', fontWeight: '400',
}, },
md: { md: {
fontSize: 15, fontSize: 15,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '400', fontWeight: '400',
}, },
'md-medium': { 'md-medium': {
fontSize: 15, fontSize: 15,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '500', fontWeight: '500',
}, },
'md-bold': { 'md-bold': {
fontSize: 15, fontSize: 15,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '700', fontWeight: '700',
}, },
'md-heavy': { 'md-heavy': {
fontSize: 15, fontSize: 15,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '800', fontWeight: '800',
}, },
'sm-thin': { 'sm-thin': {
fontSize: 14, fontSize: 14,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '300', fontWeight: '400',
}, },
sm: { sm: {
fontSize: 14, fontSize: 14,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '400', fontWeight: '400',
}, },
'sm-medium': { 'sm-medium': {
fontSize: 14, fontSize: 14,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '500', fontWeight: '500',
}, },
'sm-bold': { 'sm-bold': {
fontSize: 14, fontSize: 14,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '700', fontWeight: '700',
}, },
'sm-heavy': { 'sm-heavy': {
fontSize: 14, fontSize: 14,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '800', fontWeight: '800',
}, },
'xs-thin': { 'xs-thin': {
fontSize: 13, fontSize: 13,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '300', fontWeight: '400',
}, },
xs: { xs: {
fontSize: 13, fontSize: 13,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '400', fontWeight: '400',
}, },
'xs-medium': { 'xs-medium': {
fontSize: 13, fontSize: 13,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '500', fontWeight: '500',
}, },
'xs-bold': { 'xs-bold': {
fontSize: 13, fontSize: 13,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '700', fontWeight: '700',
}, },
'xs-heavy': { 'xs-heavy': {
fontSize: 13, fontSize: 13,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '800', fontWeight: '800',
}, },
'title-2xl': { 'title-2xl': {
fontSize: 34, fontSize: 34,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '500', fontWeight: '500',
}, },
'title-xl': { 'title-xl': {
fontSize: 28, fontSize: 28,
letterSpacing: 0.25, letterSpacing: tokens.TRACKING,
fontWeight: '500', fontWeight: '500',
}, },
'title-lg': { 'title-lg': {
@@ -254,32 +255,32 @@ export const defaultTheme: Theme = {
title: { title: {
fontWeight: '500', fontWeight: '500',
fontSize: 20, fontSize: 20,
letterSpacing: 0.15, letterSpacing: tokens.TRACKING,
}, },
'title-sm': { 'title-sm': {
fontWeight: 'bold', fontWeight: 'bold',
fontSize: 17, fontSize: 17,
letterSpacing: 0.15, letterSpacing: tokens.TRACKING,
}, },
'post-text': { 'post-text': {
fontSize: 16, fontSize: 16,
letterSpacing: 0.2, letterSpacing: tokens.TRACKING,
fontWeight: '400', fontWeight: '400',
}, },
'post-text-lg': { 'post-text-lg': {
fontSize: 20, fontSize: 20,
letterSpacing: 0.2, letterSpacing: tokens.TRACKING,
fontWeight: '400', fontWeight: '400',
}, },
'button-lg': { 'button-lg': {
fontWeight: '500', fontWeight: '500',
fontSize: 18, fontSize: 18,
letterSpacing: 0.5, letterSpacing: tokens.TRACKING,
}, },
button: { button: {
fontWeight: '500', fontWeight: '500',
fontSize: 14, fontSize: 14,
letterSpacing: 0.5, letterSpacing: tokens.TRACKING,
}, },
mono: { mono: {
fontSize: 14, fontSize: 14,
+6 -8
View File
@@ -1,6 +1,6 @@
import {beforeAll, describe, expect, jest, test} from '@jest/globals'
import * as Sentry from '@sentry/react-native'
import {nanoid} from 'nanoid/non-secure' import {nanoid} from 'nanoid/non-secure'
import {jest, describe, expect, test, beforeAll} from '@jest/globals'
import {Native as Sentry} from 'sentry-expo'
import {Logger, LogLevel, sentryTransport} from '#/logger' import {Logger, LogLevel, sentryTransport} from '#/logger'
@@ -16,12 +16,10 @@ jest.mock('#/env', () => ({
LOG_DEBUG: '', LOG_DEBUG: '',
})) }))
jest.mock('sentry-expo', () => ({ jest.mock('@sentry/react-native', () => ({
Native: { addBreadcrumb: jest.fn(),
addBreadcrumb: jest.fn(), captureException: jest.fn(),
captureException: jest.fn(), captureMessage: jest.fn(),
captureMessage: jest.fn(),
},
})) }))
beforeAll(() => { beforeAll(() => {
+1 -1
View File
@@ -1 +1 @@
export {Native as Sentry} from 'sentry-expo' export * as Sentry from '@sentry/react-native'
+1 -1
View File
@@ -1 +1 @@
export {Browser as Sentry} from 'sentry-expo' export * as Sentry from '@sentry/react-native'
+155 -57
View File
@@ -14,17 +14,21 @@ 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 ToggleButton from '#/components/forms/ToggleButton' import * as ToggleButton from '#/components/forms/ToggleButton'
import {Props as SVGIconProps} from '#/components/icons/common'
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'
import {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/TextSize'
import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase'
import {Text} from '#/components/Typography' 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 {isTabletOrMobile} = useWebMediaQueries() const {isTabletOrMobile} = useWebMediaQueries()
const {fonts} = useAlf()
const {colorMode, darkTheme} = useThemePrefs() const {colorMode, darkTheme} = useThemePrefs()
const {setColorMode, setDarkTheme} = useSetThemePrefs() const {setColorMode, setDarkTheme} = useSetThemePrefs()
@@ -54,6 +58,22 @@ export function AppearanceSettingsScreen({}: Props) {
[setDarkTheme, darkTheme], [setDarkTheme, darkTheme],
) )
const onChangeFontFamily = useCallback(
(values: string[]) => {
const next = values[0] === 'system' ? 'system' : 'theme'
fonts.setFontFamily(next)
},
[fonts],
)
const onChangeFontScale = useCallback(
(values: string[]) => {
const next = values[0] || ('0' as any)
fonts.setFontScale(next)
},
[fonts],
)
return ( return (
<LayoutAnimationConfig skipExiting skipEntering> <LayoutAnimationConfig skipExiting skipEntering>
<View testID="preferencesThreadsScreen" style={s.hContentRegion}> <View testID="preferencesThreadsScreen" style={s.hContentRegion}>
@@ -71,65 +91,143 @@ export function AppearanceSettingsScreen({}: Props) {
</View> </View>
</SimpleViewHeader> </SimpleViewHeader>
<View style={[a.p_xl, a.gap_lg]}> <View style={[a.gap_3xl, a.pt_xl, a.px_xl]}>
<View style={[a.flex_row, a.align_center, a.gap_md]}> <View style={[a.gap_lg]}>
<PhoneIcon style={t.atoms.text} /> <AppearanceToggleButtonGroup
<Text style={a.text_md}> title={_(msg`Color mode`)}
<Trans>Mode</Trans> icon={PhoneIcon}
</Text> items={[
</View> {
<ToggleButton.Group label: _(msg`System`),
label={_(msg`Dark mode`)} name: 'system',
values={[colorMode]} },
onChange={onChangeAppearance}> {
<ToggleButton.Button label={_(msg`System`)} name="system"> label: _(msg`Light`),
<ToggleButton.ButtonText> name: 'light',
<Trans>System</Trans> },
</ToggleButton.ButtonText> {
</ToggleButton.Button> label: _(msg`Dark`),
<ToggleButton.Button label={_(msg`Light`)} name="light"> name: 'dark',
<ToggleButton.ButtonText> },
<Trans>Light</Trans> ]}
</ToggleButton.ButtonText> values={[colorMode]}
</ToggleButton.Button> onChange={onChangeAppearance}
<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 {colorMode !== 'light' && (
label={_(msg`Dark theme`)} <Animated.View
values={[darkTheme ?? 'dim']} entering={native(FadeInDown)}
onChange={onChangeDarkTheme}> exiting={native(FadeOutDown)}>
<ToggleButton.Button label={_(msg`Dim`)} name="dim"> <AppearanceToggleButtonGroup
<ToggleButton.ButtonText> title={_(msg`Dark theme`)}
<Trans>Dim</Trans> icon={MoonIcon}
</ToggleButton.ButtonText> items={[
</ToggleButton.Button> {
<ToggleButton.Button label={_(msg`Dark`)} name="dark"> label: _(msg`Dim`),
<ToggleButton.ButtonText> name: 'dim',
<Trans>Dark</Trans> },
</ToggleButton.ButtonText> {
</ToggleButton.Button> label: _(msg`Dark`),
</ToggleButton.Group> name: 'dark',
</Animated.View> },
)} ]}
values={[darkTheme ?? 'dim']}
onChange={onChangeDarkTheme}
/>
</Animated.View>
)}
<AppearanceToggleButtonGroup
title={_(msg`Font`)}
description={_(
msg`For the best experience, we recommend using the theme font.`,
)}
icon={Aa}
items={[
{
label: _(msg`System`),
name: 'system',
},
{
label: _(msg`Theme`),
name: 'theme',
},
]}
values={[fonts.family]}
onChange={onChangeFontFamily}
/>
<AppearanceToggleButtonGroup
title={_(msg`Font size`)}
icon={TextSize}
items={[
{
label: _(msg`Smaller`),
name: '-1',
},
{
label: _(msg`Default`),
name: '0',
},
{
label: _(msg`Larger`),
name: '1',
},
]}
values={[fonts.scale]}
onChange={onChangeFontScale}
/>
</View>
</View> </View>
</ScrollView> </ScrollView>
</View> </View>
</LayoutAnimationConfig> </LayoutAnimationConfig>
) )
} }
export function AppearanceToggleButtonGroup({
title,
description,
icon: Icon,
items,
values,
onChange,
}: {
title: string
description?: string
icon: React.ComponentType<SVGIconProps>
items: {
label: string
name: string
}[]
values: string[]
onChange: (values: string[]) => void
}) {
const t = useTheme()
return (
<View style={[a.gap_md]}>
<View style={[a.gap_xs]}>
<View style={[a.flex_row, a.align_center, a.gap_md]}>
<Icon style={t.atoms.text} />
<Text style={[a.text_md, a.font_bold]}>{title}</Text>
</View>
{description && (
<Text
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
{description}
</Text>
)}
</View>
<ToggleButton.Group label={title} values={values} onChange={onChange}>
{items.map(item => (
<ToggleButton.Button
key={item.name}
label={item.label}
name={item.name}>
<ToggleButton.ButtonText>{item.label}</ToggleButton.ButtonText>
</ToggleButton.Button>
))}
</ToggleButton.Group>
</View>
)
}
+11 -4
View File
@@ -4,15 +4,22 @@ import {BaseNux} from '#/state/queries/nuxs/types'
export enum Nux { export enum Nux {
TenMillionDialog = 'TenMillionDialog', TenMillionDialog = 'TenMillionDialog',
NeueTypography = 'NeueTypography',
} }
export const nuxNames = new Set(Object.values(Nux)) export const nuxNames = new Set(Object.values(Nux))
export type AppNux = BaseNux<{ export type AppNux =
id: Nux.TenMillionDialog | BaseNux<{
data: undefined id: Nux.TenMillionDialog
}> data: undefined
}>
| BaseNux<{
id: Nux.NeueTypography
data: undefined
}>
export const NuxSchemas: Record<Nux, zod.ZodObject<any> | undefined> = { export const NuxSchemas: Record<Nux, zod.ZodObject<any> | undefined> = {
[Nux.TenMillionDialog]: undefined, [Nux.TenMillionDialog]: undefined,
[Nux.NeueTypography]: undefined,
} }
@@ -48,7 +48,7 @@ export function useComposerKeyboardShortcut() {
function handler(event: KeyboardEvent) { function handler(event: KeyboardEvent) {
if (shouldIgnore(event)) return if (shouldIgnore(event)) return
if ( if (
openDialogs.current.size > 0 || openDialogs?.current.size > 0 ||
isModalActive || isModalActive ||
activeLightbox || activeLightbox ||
isDrawerOpen isDrawerOpen
+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.
+2
View File
@@ -2,5 +2,7 @@
* 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: '-2' | '-1' | '0' | '1' | '2'
fontFamily: 'system' | 'theme'
lastNuxDialog: string | undefined lastNuxDialog: string | undefined
} }
+38 -9
View File
@@ -1,10 +1,11 @@
import React from 'react' import React from 'react'
import {Text as RNText, TextProps} from 'react-native' import {StyleSheet, Text as RNText, TextProps} from 'react-native'
import {UITextView} from 'react-native-uitextview' import {UITextView} from 'react-native-uitextview'
import {lh, s} from 'lib/styles' import {lh, s} from 'lib/styles'
import {TypographyVariant, useTheme} from 'lib/ThemeContext' import {TypographyVariant, useTheme} from 'lib/ThemeContext'
import {isIOS, isWeb} from 'platform/detection' import {isIOS, isWeb} from 'platform/detection'
import {applyFonts, useAlf} from '#/alf'
export type CustomTextProps = TextProps & { export type CustomTextProps = TextProps & {
type?: TypographyVariant type?: TypographyVariant
@@ -32,11 +33,28 @@ export function Text({
const theme = useTheme() const theme = useTheme()
const typography = theme.typography[type] const typography = theme.typography[type]
const lineHeightStyle = lineHeight ? lh(theme, type, lineHeight) : undefined const lineHeightStyle = lineHeight ? lh(theme, type, lineHeight) : undefined
const {fonts} = useAlf()
if (selectable && isIOS) { if (selectable && isIOS) {
const flattened = StyleSheet.flatten([
s.black,
typography,
lineHeightStyle,
style,
])
applyFonts(flattened, fonts.family)
// should always be defined on `typography`
// @ts-ignore
if (flattened.fontSize) {
// @ts-ignore
flattened.fontSize = flattened.fontSize * fonts.scaleMultiplier
}
return ( return (
<UITextView <UITextView
style={[s.black, typography, lineHeightStyle, style]} style={flattened}
selectable={selectable} selectable={selectable}
uiTextView uiTextView
{...props}> {...props}>
@@ -45,15 +63,26 @@ export function Text({
) )
} }
const flattened = StyleSheet.flatten([
s.black,
typography,
isWeb && fontFamilyStyle,
lineHeightStyle,
style,
])
applyFonts(flattened, fonts.family)
// should always be defined on `typography`
// @ts-ignore
if (flattened.fontSize) {
// @ts-ignore
flattened.fontSize = flattened.fontSize * fonts.scaleMultiplier
}
return ( return (
<RNText <RNText
style={[ style={flattened}
s.black,
typography,
isWeb && fontFamilyStyle,
lineHeightStyle,
style,
]}
// @ts-ignore web only -esb // @ts-ignore web only -esb
dataSet={Object.assign({tooltip: title}, dataSet || {})} dataSet={Object.assign({tooltip: title}, dataSet || {})}
selectable={selectable} selectable={selectable}
+12 -226
View File
@@ -3887,7 +3887,7 @@
dependencies: dependencies:
cross-spawn "^6.0.5" cross-spawn "^6.0.5"
"@expo/spawn-async@^1.5.0", "@expo/spawn-async@^1.7.0", "@expo/spawn-async@^1.7.2": "@expo/spawn-async@^1.5.0", "@expo/spawn-async@^1.7.2":
version "1.7.2" version "1.7.2"
resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.7.2.tgz#fcfe66c3e387245e72154b1a7eae8cada6a47f58" resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.7.2.tgz#fcfe66c3e387245e72154b1a7eae8cada6a47f58"
integrity sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew== integrity sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==
@@ -6034,26 +6034,6 @@
"@sentry/types" "7.119.0" "@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0" "@sentry/utils" "7.119.0"
"@sentry-internal/tracing@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.52.0.tgz#c4e0750ad0c3949c5bb4b59cbb708b0fef274080"
integrity sha512-o1YPcRGtC9tjeFCvWRJsbgK94zpExhzfxWaldAKvi3PuWEmPeewSdO/Q5pBIY1QonvSI+Q3gysLRcVlLYHhO5A==
dependencies:
"@sentry/core" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
tslib "^1.9.3"
"@sentry-internal/tracing@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.52.1.tgz#c98823afd2f9814466fa26f24a1a54fe63b27c24"
integrity sha512-6N99rE+Ek0LgbqSzI/XpsKSLUyJjQ9nychViy+MP60p1x+hllukfTsDbNtUNrPlW0Bx+vqUrWKkAqmTFad94TQ==
dependencies:
"@sentry/core" "7.52.1"
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
tslib "^1.9.3"
"@sentry/babel-plugin-component-annotate@2.20.1": "@sentry/babel-plugin-component-annotate@2.20.1":
version "2.20.1" version "2.20.1"
resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.20.1.tgz#204c63ed006a048f48f633876e1b8bacf87a9722" resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.20.1.tgz#204c63ed006a048f48f633876e1b8bacf87a9722"
@@ -6073,30 +6053,6 @@
"@sentry/types" "7.119.0" "@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0" "@sentry/utils" "7.119.0"
"@sentry/browser@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.52.0.tgz#55d266c89ed668389ff687e5cc885c27016ea85c"
integrity sha512-Sib0T24cQCqqqAhg+nZdfI7qNYGE03jiM3RbY7yG5UoycdnJzWEwrBVSzRTgg3Uya9TRTEGJ+d9vxPIU5TL7TA==
dependencies:
"@sentry-internal/tracing" "7.52.0"
"@sentry/core" "7.52.0"
"@sentry/replay" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
tslib "^1.9.3"
"@sentry/browser@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.52.1.tgz#f112ca4170bb5023f050bdcbcce5621b475a46eb"
integrity sha512-HrCOfieX68t+Wj42VIkraLYwx8kN5311SdBkHccevWs2Y2dZU7R9iLbI87+nb5kpOPQ7jVWW7d6QI/yZmliYgQ==
dependencies:
"@sentry-internal/tracing" "7.52.1"
"@sentry/core" "7.52.1"
"@sentry/replay" "7.52.1"
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
tslib "^1.9.3"
"@sentry/cli-darwin@2.36.1": "@sentry/cli-darwin@2.36.1":
version "2.36.1" version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.36.1.tgz#786adf6984dbe3c6fb7dac51b625c314117b807d" resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.36.1.tgz#786adf6984dbe3c6fb7dac51b625c314117b807d"
@@ -6132,17 +6088,6 @@
resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.36.1.tgz#80779b4bffb4e2e32944eae72c60e6f40151b4dc" resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.36.1.tgz#80779b4bffb4e2e32944eae72c60e6f40151b4dc"
integrity sha512-wWqht2xghcK3TGnooHZSzA3WSjdtno/xFjZLvWmw38rblGwgKMxLZnlxV6uDyS+OJ6CbfDTlCRay/0TIqA0N8g== integrity sha512-wWqht2xghcK3TGnooHZSzA3WSjdtno/xFjZLvWmw38rblGwgKMxLZnlxV6uDyS+OJ6CbfDTlCRay/0TIqA0N8g==
"@sentry/cli@2.17.5":
version "2.17.5"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.17.5.tgz#d41e24893a843bcd41e14274044a7ddea9332824"
integrity sha512-0tXjLDpaKB46851EMJ6NbP0o9/gdEaDSLAyjEtXxlVO6+RyhUj6x6jDwn0vis8n/7q0AvbIjAcJrot+TbZP+WQ==
dependencies:
https-proxy-agent "^5.0.0"
node-fetch "^2.6.7"
progress "^2.0.3"
proxy-from-env "^1.1.0"
which "^2.0.2"
"@sentry/cli@2.36.1": "@sentry/cli@2.36.1":
version "2.36.1" version "2.36.1"
resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.36.1.tgz#a9146b798cb6d2f782a7a48d74633ddcd88dc8d3" resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.36.1.tgz#a9146b798cb6d2f782a7a48d74633ddcd88dc8d3"
@@ -6170,24 +6115,6 @@
"@sentry/types" "7.119.0" "@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0" "@sentry/utils" "7.119.0"
"@sentry/core@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.52.0.tgz#6c820ca48fe2f06bfd6b290044c96de2375f2ad4"
integrity sha512-BWdG6vCMeUeMhF4ILpxXTmw70JJvT1MGJcnv09oSupWHTmqy6I19YP6YcEyFuBL4jXPN51eCl7luIdLGJrPbOg==
dependencies:
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
tslib "^1.9.3"
"@sentry/core@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.52.1.tgz#4de702937ba8944802bb06eb8dfdf089c39f6bab"
integrity sha512-36clugQu5z/9jrit1gzI7KfKbAUimjRab39JeR0mJ6pMuKLTTK7PhbpUAD4AQBs9qVeXN2c7h9SVZiSA0UDvkg==
dependencies:
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
tslib "^1.9.3"
"@sentry/hub@7.119.0": "@sentry/hub@7.119.0":
version "7.119.0" version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.119.0.tgz#a94d657b9d3cfd4cc061c5c238f86faefb55d5d8" resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.119.0.tgz#a94d657b9d3cfd4cc061c5c238f86faefb55d5d8"
@@ -6197,16 +6124,6 @@
"@sentry/types" "7.119.0" "@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0" "@sentry/utils" "7.119.0"
"@sentry/hub@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-7.52.0.tgz#ffc087d58c745d57108862faa0f701b15503dcc2"
integrity sha512-w3d8Pmp3Fx2zbbjz6hAeIbsFEkLyrUs9YTGG2y8oCoTlAtGK+AjdG+Z0H/clAZONflD/je2EmFHCI0EuXE9tEw==
dependencies:
"@sentry/core" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
tslib "^1.9.3"
"@sentry/integrations@7.119.0": "@sentry/integrations@7.119.0":
version "7.119.0" version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.119.0.tgz#5b25c603026dbacfe1ae7bb8d768506a129149fb" resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.119.0.tgz#5b25c603026dbacfe1ae7bb8d768506a129149fb"
@@ -6217,26 +6134,6 @@
"@sentry/utils" "7.119.0" "@sentry/utils" "7.119.0"
localforage "^1.8.1" localforage "^1.8.1"
"@sentry/integrations@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.52.0.tgz#632aa5e54bdfdab910a24057c2072634a2670409"
integrity sha512-tqxYzgc71XdFD8MTCsVMCPef08lPY9jULE5Zi7TzjyV2AItDRJPkixG0qjwjOGwCtN/6KKz0lGPGYU8ZDxvsbg==
dependencies:
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
localforage "^1.8.1"
tslib "^1.9.3"
"@sentry/integrations@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.52.1.tgz#e8a5988477e8d295fa1d90ce5628c1a7794c2a09"
integrity sha512-4uejF01723wzEHjcP5AcNcV+Z/6U27b1LyaDu0jY3XDry98MMjhS/ASzecLpaEFxi3dh/jMTUrNp1u7WMj59Lg==
dependencies:
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
localforage "^1.8.1"
tslib "^1.9.3"
"@sentry/react-native@5.32.0": "@sentry/react-native@5.32.0":
version "5.32.0" version "5.32.0"
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-5.32.0.tgz#14c46a65f7359f5e74a9cef7edb9d7bf9a0a449d" resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-5.32.0.tgz#14c46a65f7359f5e74a9cef7edb9d7bf9a0a449d"
@@ -6252,20 +6149,6 @@
"@sentry/types" "7.119.0" "@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0" "@sentry/utils" "7.119.0"
"@sentry/react-native@5.5.0":
version "5.5.0"
resolved "https://registry.yarnpkg.com/@sentry/react-native/-/react-native-5.5.0.tgz#b1283f68465b1772ad6059ebba149673cef33f2d"
integrity sha512-xrES+OAIu3HFhoQSuJjd16Hh02/mByuNoKUjF7e4WDGIiTew3aqlqeLjU7x4npmg5Vbt+ND5jR12u/NmdfArwg==
dependencies:
"@sentry/browser" "7.52.0"
"@sentry/cli" "2.17.5"
"@sentry/core" "7.52.0"
"@sentry/hub" "7.52.0"
"@sentry/integrations" "7.52.0"
"@sentry/react" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
"@sentry/react@7.119.0": "@sentry/react@7.119.0":
version "7.119.0" version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.119.0.tgz#79f2c9d94322a3afbfa8af9f5b872f7c2e9b0820" resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.119.0.tgz#79f2c9d94322a3afbfa8af9f5b872f7c2e9b0820"
@@ -6277,28 +6160,6 @@
"@sentry/utils" "7.119.0" "@sentry/utils" "7.119.0"
hoist-non-react-statics "^3.3.2" hoist-non-react-statics "^3.3.2"
"@sentry/react@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.52.0.tgz#d12d270ec82dea0474e69deb9112181affe7c524"
integrity sha512-VQxquyFFlvB81k7UER7tTJxjzbczNI2jqsw6nN1TVDrAIDt8/hT2x7m/M0FlWc88roBKuaMmbvzfNGWaL9abyQ==
dependencies:
"@sentry/browser" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
hoist-non-react-statics "^3.3.2"
tslib "^1.9.3"
"@sentry/react@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.52.1.tgz#5f30919f4680493558c5233165b2092d2b59f6d1"
integrity sha512-RRH+GJE5TNg5QS86bSjSZuR2snpBTOO5/SU9t4BOqZMknzhMVTClGMm84hffJa9pMPMJPQ2fWQAbhrlD8RcF6w==
dependencies:
"@sentry/browser" "7.52.1"
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
hoist-non-react-statics "^3.3.2"
tslib "^1.9.3"
"@sentry/replay@7.119.0": "@sentry/replay@7.119.0":
version "7.119.0" version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.119.0.tgz#50881079d013c77f87a994331d8bcad1d49e0960" resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.119.0.tgz#50881079d013c77f87a994331d8bcad1d49e0960"
@@ -6309,39 +6170,11 @@
"@sentry/types" "7.119.0" "@sentry/types" "7.119.0"
"@sentry/utils" "7.119.0" "@sentry/utils" "7.119.0"
"@sentry/replay@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.52.0.tgz#4d78e88282d2c1044ea4b648a68d1b22173e810d"
integrity sha512-RRPALjDST2s7MHiMcUJ7Wo4WW7EWfUDYSG0LuhMT8DNc+ZsxQoFsLYX/yz8b3f0IUSr7xKBXP+aPeIy3jDAS2g==
dependencies:
"@sentry/core" "7.52.0"
"@sentry/types" "7.52.0"
"@sentry/utils" "7.52.0"
"@sentry/replay@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.52.1.tgz#272a0bcb79bb9ffce99b5dcaf864f18d729ce0da"
integrity sha512-A+RaUmpU9/yBHnU3ATemc6wAvobGno0yf5R6fZYkAFoo2FCR2YG6AXxkTazymIf8v2DnLGaSDORYDPdhQClU9A==
dependencies:
"@sentry/core" "7.52.1"
"@sentry/types" "7.52.1"
"@sentry/utils" "7.52.1"
"@sentry/types@7.119.0": "@sentry/types@7.119.0":
version "7.119.0" version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.119.0.tgz#8b3d7a1405c362e75cd900d46089df4e70919d2a" resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.119.0.tgz#8b3d7a1405c362e75cd900d46089df4e70919d2a"
integrity sha512-27qQbutDBPKGbuJHROxhIWc1i0HJaGLA90tjMu11wt0E4UNxXRX+UQl4Twu68v4EV3CPvQcEpQfgsViYcXmq+w== integrity sha512-27qQbutDBPKGbuJHROxhIWc1i0HJaGLA90tjMu11wt0E4UNxXRX+UQl4Twu68v4EV3CPvQcEpQfgsViYcXmq+w==
"@sentry/types@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.52.0.tgz#b7d5372f17355e3991cbe818ad567f3fe277cc6b"
integrity sha512-XnEWpS6P6UdP1FqbmeqhI96Iowqd2jM5R7zJ97txTdAd5NmdHHH0pODTR9NiQViA1WlsXDut7ZLxgPzC9vIcMA==
"@sentry/types@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.52.1.tgz#bcff6d0462d9b9b7b9ec31c0068fe02d44f25da2"
integrity sha512-OMbGBPrJsw0iEXwZ2bJUYxewI1IEAU2e1aQGc0O6QW5+6hhCh+8HO8Xl4EymqwejjztuwStkl6G1qhK+Q0/Row==
"@sentry/utils@7.119.0": "@sentry/utils@7.119.0":
version "7.119.0" version "7.119.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.119.0.tgz#debe29020f6ef3786a5bd855cf1b97116b7be826" resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.119.0.tgz#debe29020f6ef3786a5bd855cf1b97116b7be826"
@@ -6349,22 +6182,6 @@
dependencies: dependencies:
"@sentry/types" "7.119.0" "@sentry/types" "7.119.0"
"@sentry/utils@7.52.0":
version "7.52.0"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.52.0.tgz#cacc36d905036ba7084c14965e964fc44239d7f0"
integrity sha512-X1NHYuqW0qpZfP731YcVe+cn36wJdAeBHPYPIkXCl4o4GePCJfH/CM/+9V9cZykNjyLrs2Xy/TavSAHNCj8j7w==
dependencies:
"@sentry/types" "7.52.0"
tslib "^1.9.3"
"@sentry/utils@7.52.1":
version "7.52.1"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.52.1.tgz#4a3e49b918f78dba4524c924286210259020cac5"
integrity sha512-MPt1Xu/jluulknW8CmZ2naJ53jEdtdwCBSo6fXJvOTI0SDqwIPbXDVrsnqLAhVJuIN7xbkj96nuY/VBR6S5sWg==
dependencies:
"@sentry/types" "7.52.1"
tslib "^1.9.3"
"@sideway/address@^4.1.3": "@sideway/address@^4.1.3":
version "4.1.4" version "4.1.4"
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0"
@@ -12402,6 +12219,13 @@ expo-file-system@^17.0.1, expo-file-system@~17.0.1:
resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-17.0.1.tgz#b9f8af8c1c06ec71d96fd7a0d2567fa9e1c88f15" resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-17.0.1.tgz#b9f8af8c1c06ec71d96fd7a0d2567fa9e1c88f15"
integrity sha512-dYpnZJqTGj6HCYJyXAgpFkQWsiCH3HY1ek2cFZVHFoEc5tLz9gmdEgTF6nFHurvmvfmXqxi7a5CXyVm0aFYJBw== integrity sha512-dYpnZJqTGj6HCYJyXAgpFkQWsiCH3HY1ek2cFZVHFoEc5tLz9gmdEgTF6nFHurvmvfmXqxi7a5CXyVm0aFYJBw==
expo-font@~12.0.10:
version "12.0.10"
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-12.0.10.tgz#62deaf1f46159d7839f01305f44079268781b1db"
integrity sha512-Q1i2NuYri3jy32zdnBaHHCya1wH1yMAsI+3CCmj9zlQzlhsS9Bdwcj2W3c5eU5FvH2hsNQy4O+O1NnM6o/pDaQ==
dependencies:
fontfaceobserver "^2.1.0"
expo-font@~12.0.5: expo-font@~12.0.5:
version "12.0.5" version "12.0.5"
resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-12.0.5.tgz#3451c2bd3f98859b127a6484d3474a292889b93f" resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-12.0.5.tgz#3451c2bd3f98859b127a6484d3474a292889b93f"
@@ -20243,19 +20067,6 @@ send@0.18.0, send@^0.18.0:
range-parser "~1.2.1" range-parser "~1.2.1"
statuses "2.0.1" statuses "2.0.1"
sentry-expo@~7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/sentry-expo/-/sentry-expo-7.0.1.tgz#025f0e90ab7f7cba1e00c892fabc027de21bc5bc"
integrity sha512-8vmOy4R+qM1peQA9EP8rDGUMBhgMU1D5FyuWY9kfNGatmWuvEmlZpVgaXoXaNPIhPgf2TMrvQIlbqLHtTkoeSA==
dependencies:
"@expo/spawn-async" "^1.7.0"
"@sentry/integrations" "7.52.1"
"@sentry/react" "7.52.1"
"@sentry/react-native" "5.5.0"
"@sentry/types" "7.52.1"
mkdirp "^1.0.4"
rimraf "^3.0.2"
serialize-error@^2.1.0: serialize-error@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-2.1.0.tgz#50b679d5635cdf84667bdc8e59af4e5b81d5f60a"
@@ -20807,16 +20618,7 @@ string-natural-compare@^3.0.1:
resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4" resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
"string-width-cjs@npm:string-width@^4.2.0": "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3" version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -20925,7 +20727,7 @@ stringify-object@^3.3.0:
is-obj "^1.0.1" is-obj "^1.0.1"
is-regexp "^1.0.0" is-regexp "^1.0.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1": "strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1" version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -20939,13 +20741,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.2.0:
dependencies: dependencies:
ansi-regex "^4.1.0" ansi-regex "^4.1.0"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^7.0.1: strip-ansi@^7.0.1:
version "7.1.0" version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
@@ -21553,7 +21348,7 @@ tsconfig-paths@^3.14.2:
minimist "^1.2.6" minimist "^1.2.6"
strip-bom "^3.0.0" strip-bom "^3.0.0"
tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
@@ -22661,7 +22456,7 @@ workbox-window@6.6.1:
"@types/trusted-types" "^2.0.2" "@types/trusted-types" "^2.0.2"
workbox-core "6.6.1" workbox-core "6.6.1"
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0" version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -22679,15 +22474,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0" string-width "^4.1.0"
strip-ansi "^6.0.0" strip-ansi "^6.0.0"
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: wrap-ansi@^8.0.1, wrap-ansi@^8.1.0:
version "8.1.0" version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"