···63### Tips
6465- Copy the `.env.example` to `.env` and fill in any necessary tokens. (The Sentry token is NOT required; see instructions below if you want to enable Sentry.)
66-- To run on the device, add `--device` to the command (e.g. `yarn android --device`). To build in production mode (slower build, faster app), also add `--variant release`.
67- If you want to use Expo EAS on your own builds without ejecting from Expo, make sure to change the `owner` and `extra.eas.projectId` properties. If you do not have an Expo account, you may remove these properties.
68- `npx react-native info` Checks what has been installed.
69- If the Android simulator frequently hangs or is very sluggish, [bump its memory limit](https://stackoverflow.com/a/40068396)
···164- TextEncoder / TextDecoder
165- react-native-url-polyfill
166- Array#findLast (on web)
167-- atob (on native)
168169### Sentry sourcemaps
170
···63### Tips
6465- Copy the `.env.example` to `.env` and fill in any necessary tokens. (The Sentry token is NOT required; see instructions below if you want to enable Sentry.)
66+- To run on the device, add `--device` to the command (e.g. `yarn android --device`). To build in production mode (slower build, faster app), also add `--variant release` on Android or `--configuration Release` on iOS.
67- If you want to use Expo EAS on your own builds without ejecting from Expo, make sure to change the `owner` and `extra.eas.projectId` properties. If you do not have an Expo account, you may remove these properties.
68- `npx react-native info` Checks what has been installed.
69- If the Android simulator frequently hangs or is very sluggish, [bump its memory limit](https://stackoverflow.com/a/40068396)
···164- TextEncoder / TextDecoder
165- react-native-url-polyfill
166- Array#findLast (on web)
0167168### Sentry sourcemaps
169
···1import ExpoModulesCore
023// This view will be used as a native component. Make sure to inherit from `ExpoView`
4// to apply the proper styling (e.g. border radius and shadows).
···1import ExpoModulesCore
2+import React
34// This view will be used as a native component. Make sure to inherit from `ExpoView`
5// to apply the proper styling (e.g. border radius and shadows).
···2 Children,
3 cloneElement,
4 isValidElement,
5- type ReactElement,
6- type ReactNode,
7 useCallback,
8 useEffect,
9 useMemo,
···26 * screen reader support is enabled. THIS SHOULD BE USED SPARINGLY, only when
27 * no better option is available.
28 */
29-export function FocusScope({children}: {children: ReactNode}) {
30 const {screenReaderEnabled} = useA11y()
3132 return screenReaderEnabled ? <FocusTrap>{children}</FocusTrap> : children
···41 * they have reached the start or end of the content and tell them how to
42 * remain within the active content section.
43 */
44-function FocusTrap({children}: {children: ReactNode}) {
45 const {_} = useLingui()
46 const child = useRef<View>(null)
47···53 const decoratedChildren = useMemo(() => {
54 return Children.toArray(children).map((node, i) => {
55 if (i === 0 && isValidElement(node)) {
56- const n = node as ReactElement<any>
57 if (n.props.ref !== undefined) {
58 throw new Error(
59 'FocusScope needs to override the ref on its first child.',
···2 Children,
3 cloneElement,
4 isValidElement,
005 useCallback,
6 useEffect,
7 useMemo,
···24 * screen reader support is enabled. THIS SHOULD BE USED SPARINGLY, only when
25 * no better option is available.
26 */
27+export function FocusScope({children}: {children: React.ReactNode}) {
28 const {screenReaderEnabled} = useA11y()
2930 return screenReaderEnabled ? <FocusTrap>{children}</FocusTrap> : children
···39 * they have reached the start or end of the content and tell them how to
40 * remain within the active content section.
41 */
42+function FocusTrap({children}: {children: React.ReactNode}) {
43 const {_} = useLingui()
44 const child = useRef<View>(null)
45···51 const decoratedChildren = useMemo(() => {
52 return Children.toArray(children).map((node, i) => {
53 if (i === 0 && isValidElement(node)) {
54+ const n = node as React.ReactElement<any>
55 if (n.props.ref !== undefined) {
56 throw new Error(
57 'FocusScope needs to override the ref on its first child.',
+1-2
src/components/FocusScope/index.web.tsx
···1-import {type ReactNode} from 'react'
2import {FocusScope as RadixFocusScope} from 'radix-ui/internal'
34/*
···6 * use this in Dialogs and such already. It's here as a convenient counterpart
7 * to the hacky native solution.
8 */
9-export function FocusScope({children}: {children: ReactNode}) {
10 return (
11 <RadixFocusScope.FocusScope loop asChild trapped>
12 {children}
···01import {FocusScope as RadixFocusScope} from 'radix-ui/internal'
23/*
···5 * use this in Dialogs and such already. It's here as a convenient counterpart
6 * to the hacky native solution.
7 */
8+export function FocusScope({children}: {children: React.ReactNode}) {
9 return (
10 <RadixFocusScope.FocusScope loop asChild trapped>
11 {children}
···1-import {copyAsync} from 'expo-file-system'
2import {type BskyAgent, type ComAtprotoRepoUploadBlob} from '@atproto/api'
34import {safeDeleteAsync} from '#/lib/media/manip'
···1+import {copyAsync} from 'expo-file-system/legacy'
2import {type BskyAgent, type ComAtprotoRepoUploadBlob} from '@atproto/api'
34import {safeDeleteAsync} from '#/lib/media/manip'
-15
src/lib/hooks/useAnimatedScrollHandler_FIXED.ts
···1-// Be warned. This Hook is very buggy unless used in a very constrained way.
2-// To use it safely:
3-//
4-// - DO NOT pass its return value as a prop to any user-defined component.
5-// - DO NOT pass its return value to more than a single component.
6-//
7-// In other words, the only safe way to use it is next to the leaf Reanimated View.
8-//
9-// Relevant bug reports:
10-// - https://github.com/software-mansion/react-native-reanimated/issues/5345
11-// - https://github.com/software-mansion/react-native-reanimated/issues/5360
12-// - https://github.com/software-mansion/react-native-reanimated/issues/5364
13-//
14-// It's great when it works though.
15-export {useAnimatedScrollHandler} from 'react-native-reanimated'
···10 makeDirectoryAsync,
11 StorageAccessFramework,
12 writeAsStringAsync,
13-} from 'expo-file-system'
14import {manipulateAsync, SaveFormat} from 'expo-image-manipulator'
15import * as MediaLibrary from 'expo-media-library'
16import * as Sharing from 'expo-sharing'
···10 makeDirectoryAsync,
11 StorageAccessFramework,
12 writeAsStringAsync,
13+} from 'expo-file-system/legacy'
14import {manipulateAsync, SaveFormat} from 'expo-image-manipulator'
15import * as MediaLibrary from 'expo-media-library'
16import * as Sharing from 'expo-sharing'
···2 documentDirectory,
3 getInfoAsync,
4 readDirectoryAsync,
5-} from 'expo-file-system'
6import ExpoImageCropTool, {type OpenCropperOptions} from 'expo-image-crop-tool'
78import {compressIfNeeded} from './manip'
···2 documentDirectory,
3 getInfoAsync,
4 readDirectoryAsync,
5+} from 'expo-file-system/legacy'
6import ExpoImageCropTool, {type OpenCropperOptions} from 'expo-image-crop-tool'
78import {compressIfNeeded} from './manip'
+1-1
src/lib/media/video/upload.ts
···1-import {createUploadTask, FileSystemUploadType} from 'expo-file-system'
2import {type AppBskyVideoDefs, type BskyAgent} from '@atproto/api'
3import {type I18n} from '@lingui/core'
4import {msg} from '@lingui/macro'
···1+import {createUploadTask, FileSystemUploadType} from 'expo-file-system/legacy'
2import {type AppBskyVideoDefs, type BskyAgent} from '@atproto/api'
3import {type I18n} from '@lingui/core'
4import {msg} from '@lingui/macro'
+16-16
src/locale/locales/en/messages.po
···216msgid "{0}s"
217msgstr ""
218219-#: src/view/shell/desktop/LeftNav.tsx:455
220msgid "{count, plural, one {# unread item} other {# unread items}}"
221msgstr ""
222···1740#: src/lib/hooks/useNotificationHandler.ts:99
1741#: src/Navigation.tsx:549
1742#: src/view/shell/bottom-bar/BottomBar.tsx:221
1743-#: src/view/shell/desktop/LeftNav.tsx:607
1744#: src/view/shell/Drawer.tsx:466
1745msgid "Chat"
1746msgstr ""
···2066msgid "Complete the challenge"
2067msgstr ""
20682069-#: src/view/shell/desktop/LeftNav.tsx:572
2070msgid "Compose new post"
2071msgstr ""
2072···33843385#: src/Navigation.tsx:759
3386#: src/screens/Search/Shell.tsx:307
3387-#: src/view/shell/desktop/LeftNav.tsx:689
3388#: src/view/shell/Drawer.tsx:414
3389msgid "Explore"
3390msgstr ""
···3673#: src/screens/StarterPack/StarterPackScreen.tsx:190
3674#: src/view/screens/Feeds.tsx:511
3675#: src/view/screens/Profile.tsx:230
3676-#: src/view/shell/desktop/LeftNav.tsx:727
3677#: src/view/shell/Drawer.tsx:530
3678msgid "Feeds"
3679msgstr ""
···4370#: src/Navigation.tsx:754
4371#: src/Navigation.tsx:774
4372#: src/view/shell/bottom-bar/BottomBar.tsx:178
4373-#: src/view/shell/desktop/LeftNav.tsx:671
4374#: src/view/shell/Drawer.tsx:440
4375msgid "Home"
4376msgstr ""
···4997#: src/view/screens/Lists.tsx:65
4998#: src/view/screens/Profile.tsx:224
4999#: src/view/screens/Profile.tsx:232
5000-#: src/view/shell/desktop/LeftNav.tsx:745
5001#: src/view/shell/Drawer.tsx:545
5002msgid "Lists"
5003msgstr ""
···5560msgid "New post"
5561msgstr ""
55625563-#: src/view/shell/desktop/LeftNav.tsx:580
5564msgctxt "action"
5565msgid "New Post"
5566msgstr ""
···5839#: src/screens/Settings/Settings.tsx:199
5840#: src/view/screens/Notifications.tsx:130
5841#: src/view/shell/bottom-bar/BottomBar.tsx:252
5842-#: src/view/shell/desktop/LeftNav.tsx:708
5843#: src/view/shell/Drawer.tsx:493
5844msgid "Notifications"
5845msgstr ""
···6454msgid "Please explain why you think your chats were incorrectly disabled"
6455msgstr ""
64566457-#: src/components/FocusScope/index.tsx:93
6458-#: src/components/FocusScope/index.tsx:117
6459msgid "Please go back, or activate this element to return to the start of the active content."
6460msgstr ""
6461···6687msgstr ""
66886689#: src/view/shell/bottom-bar/BottomBar.tsx:316
6690-#: src/view/shell/desktop/LeftNav.tsx:786
6691#: src/view/shell/Drawer.tsx:77
6692#: src/view/shell/Drawer.tsx:596
6693msgid "Profile"
···7486msgid "Save to my feeds"
7487msgstr ""
74887489-#: src/view/shell/desktop/LeftNav.tsx:764
7490#: src/view/shell/Drawer.tsx:571
7491msgctxt "link to bookmarks screen"
7492msgid "Saved"
···79097910#: src/Navigation.tsx:213
7911#: src/screens/Settings/Settings.tsx:99
7912-#: src/view/shell/desktop/LeftNav.tsx:804
7913#: src/view/shell/Drawer.tsx:609
7914msgid "Settings"
7915msgstr ""
···10754msgid "You've found some people to follow"
10755msgstr ""
1075610757-#: src/components/FocusScope/index.tsx:114
10758msgid "You've reached the end of the active content."
10759msgstr ""
10760···10766msgid "You've reached the maximum number of requests allowed. Please try again later."
10767msgstr ""
1076810769-#: src/components/FocusScope/index.tsx:90
10770msgid "You've reached the start of the active content."
10771msgstr ""
10772
···216msgid "{0}s"
217msgstr ""
218219+#: src/view/shell/desktop/LeftNav.tsx:454
220msgid "{count, plural, one {# unread item} other {# unread items}}"
221msgstr ""
222···1740#: src/lib/hooks/useNotificationHandler.ts:99
1741#: src/Navigation.tsx:549
1742#: src/view/shell/bottom-bar/BottomBar.tsx:221
1743+#: src/view/shell/desktop/LeftNav.tsx:608
1744#: src/view/shell/Drawer.tsx:466
1745msgid "Chat"
1746msgstr ""
···2066msgid "Complete the challenge"
2067msgstr ""
20682069+#: src/view/shell/desktop/LeftNav.tsx:573
2070msgid "Compose new post"
2071msgstr ""
2072···33843385#: src/Navigation.tsx:759
3386#: src/screens/Search/Shell.tsx:307
3387+#: src/view/shell/desktop/LeftNav.tsx:690
3388#: src/view/shell/Drawer.tsx:414
3389msgid "Explore"
3390msgstr ""
···3673#: src/screens/StarterPack/StarterPackScreen.tsx:190
3674#: src/view/screens/Feeds.tsx:511
3675#: src/view/screens/Profile.tsx:230
3676+#: src/view/shell/desktop/LeftNav.tsx:728
3677#: src/view/shell/Drawer.tsx:530
3678msgid "Feeds"
3679msgstr ""
···4370#: src/Navigation.tsx:754
4371#: src/Navigation.tsx:774
4372#: src/view/shell/bottom-bar/BottomBar.tsx:178
4373+#: src/view/shell/desktop/LeftNav.tsx:672
4374#: src/view/shell/Drawer.tsx:440
4375msgid "Home"
4376msgstr ""
···4997#: src/view/screens/Lists.tsx:65
4998#: src/view/screens/Profile.tsx:224
4999#: src/view/screens/Profile.tsx:232
5000+#: src/view/shell/desktop/LeftNav.tsx:746
5001#: src/view/shell/Drawer.tsx:545
5002msgid "Lists"
5003msgstr ""
···5560msgid "New post"
5561msgstr ""
55625563+#: src/view/shell/desktop/LeftNav.tsx:581
5564msgctxt "action"
5565msgid "New Post"
5566msgstr ""
···5839#: src/screens/Settings/Settings.tsx:199
5840#: src/view/screens/Notifications.tsx:130
5841#: src/view/shell/bottom-bar/BottomBar.tsx:252
5842+#: src/view/shell/desktop/LeftNav.tsx:709
5843#: src/view/shell/Drawer.tsx:493
5844msgid "Notifications"
5845msgstr ""
···6454msgid "Please explain why you think your chats were incorrectly disabled"
6455msgstr ""
64566457+#: src/components/FocusScope/index.tsx:91
6458+#: src/components/FocusScope/index.tsx:115
6459msgid "Please go back, or activate this element to return to the start of the active content."
6460msgstr ""
6461···6687msgstr ""
66886689#: src/view/shell/bottom-bar/BottomBar.tsx:316
6690+#: src/view/shell/desktop/LeftNav.tsx:787
6691#: src/view/shell/Drawer.tsx:77
6692#: src/view/shell/Drawer.tsx:596
6693msgid "Profile"
···7486msgid "Save to my feeds"
7487msgstr ""
74887489+#: src/view/shell/desktop/LeftNav.tsx:765
7490#: src/view/shell/Drawer.tsx:571
7491msgctxt "link to bookmarks screen"
7492msgid "Saved"
···79097910#: src/Navigation.tsx:213
7911#: src/screens/Settings/Settings.tsx:99
7912+#: src/view/shell/desktop/LeftNav.tsx:805
7913#: src/view/shell/Drawer.tsx:609
7914msgid "Settings"
7915msgstr ""
···10754msgid "You've found some people to follow"
10755msgstr ""
1075610757+#: src/components/FocusScope/index.tsx:112
10758msgid "You've reached the end of the active content."
10759msgstr ""
10760···10766msgid "You've reached the maximum number of requests allowed. Please try again later."
10767msgstr ""
1076810769+#: src/components/FocusScope/index.tsx:88
10770msgid "You've reached the start of the active content."
10771msgstr ""
10772
···1import {Platform} from 'react-native'
2import {setStringAsync} from 'expo-clipboard'
3-import * as FileSystem from 'expo-file-system'
4import {Image} from 'expo-image'
5import {msg, Trans} from '@lingui/macro'
6import {useLingui} from '@lingui/react'
···1import {Platform} from 'react-native'
2import {setStringAsync} from 'expo-clipboard'
3+import * as FileSystem from 'expo-file-system/legacy'
4import {Image} from 'expo-image'
5import {msg, Trans} from '@lingui/macro'
6import {useLingui} from '@lingui/react'
···19 useAnimatedProps,
20 useAnimatedReaction,
21 useAnimatedRef,
022 useAnimatedStyle,
23 useSharedValue,
24} from 'react-native-reanimated'
25import {useSafeAreaFrame} from 'react-native-safe-area-context'
26import {Image} from 'expo-image'
2728-import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
29import {
30 type Dimensions as ImageDimensions,
31 type ImageSource,
···19 useAnimatedProps,
20 useAnimatedReaction,
21 useAnimatedRef,
22+ useAnimatedScrollHandler,
23 useAnimatedStyle,
24 useSharedValue,
25} from 'react-native-reanimated'
26import {useSafeAreaFrame} from 'react-native-safe-area-context'
27import {Image} from 'expo-image'
28029import {
30 type Dimensions as ImageDimensions,
31 type ImageSource,
+1-1
src/view/com/util/List.tsx
···3import {
4 type FlatListPropsWithLayout,
5 runOnJS,
06 useSharedValue,
7} from 'react-native-reanimated'
8import {updateActiveVideoViewAsync} from '@haileyok/bluesky-video'
910-import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
11import {useDedupe} from '#/lib/hooks/useDedupe'
12import {useScrollHandlers} from '#/lib/ScrollContext'
13import {addStyle} from '#/lib/styles'
···3import {
4 type FlatListPropsWithLayout,
5 runOnJS,
6+ useAnimatedScrollHandler,
7 useSharedValue,
8} from 'react-native-reanimated'
9import {updateActiveVideoViewAsync} from '@haileyok/bluesky-video'
10011import {useDedupe} from '#/lib/hooks/useDedupe'
12import {useScrollHandlers} from '#/lib/ScrollContext'
13import {addStyle} from '#/lib/styles'