about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/StarterPack/QrCode.tsx17
-rw-r--r--src/components/StarterPack/QrCodeDialog.tsx90
-rw-r--r--src/screens/Onboarding/StepProfile/PlaceholderCanvas.tsx22
-rw-r--r--src/screens/Onboarding/StepProfile/index.tsx16
-rw-r--r--src/screens/Onboarding/state.ts14
-rw-r--r--src/screens/Signup/StepInfo/index.tsx5
6 files changed, 97 insertions, 67 deletions
diff --git a/src/components/StarterPack/QrCode.tsx b/src/components/StarterPack/QrCode.tsx
index 8ce5cbbb1..c6408109b 100644
--- a/src/components/StarterPack/QrCode.tsx
+++ b/src/components/StarterPack/QrCode.tsx
@@ -1,18 +1,23 @@
 import React from 'react'
 import {View} from 'react-native'
 import QRCode from 'react-native-qrcode-styled'
-import ViewShot from 'react-native-view-shot'
+import type ViewShot from 'react-native-view-shot'
 import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
 import {Trans} from '@lingui/macro'
 
-import {isWeb} from 'platform/detection'
-import {Logo} from 'view/icons/Logo'
-import {Logotype} from 'view/icons/Logotype'
+import {isWeb} from '#/platform/detection'
+import {Logo} from '#/view/icons/Logo'
+import {Logotype} from '#/view/icons/Logotype'
 import {useTheme} from '#/alf'
 import {atoms as a} from '#/alf'
 import {LinearGradientBackground} from '#/components/LinearGradientBackground'
 import {Text} from '#/components/Typography'
 
+const LazyViewShot = React.lazy(
+  // @ts-expect-error dynamic import
+  () => import('react-native-view-shot/src/index'),
+)
+
 interface Props {
   starterPack: AppBskyGraphDefs.StarterPackView
   link: string
@@ -29,7 +34,7 @@ export const QrCode = React.forwardRef<ViewShot, Props>(function QrCode(
   }
 
   return (
-    <ViewShot ref={ref}>
+    <LazyViewShot ref={ref}>
       <LinearGradientBackground
         style={[
           {width: 300, minHeight: 390},
@@ -79,7 +84,7 @@ export const QrCode = React.forwardRef<ViewShot, Props>(function QrCode(
           </Text>
         </View>
       </LinearGradientBackground>
-    </ViewShot>
+    </LazyViewShot>
   )
 })
 
diff --git a/src/components/StarterPack/QrCodeDialog.tsx b/src/components/StarterPack/QrCodeDialog.tsx
index a884390bf..b2af8ff73 100644
--- a/src/components/StarterPack/QrCodeDialog.tsx
+++ b/src/components/StarterPack/QrCodeDialog.tsx
@@ -1,6 +1,6 @@
 import React from 'react'
 import {View} from 'react-native'
-import ViewShot from 'react-native-view-shot'
+import type ViewShot from 'react-native-view-shot'
 import {requestMediaLibraryPermissionsAsync} from 'expo-image-picker'
 import {createAssetAsync} from 'expo-media-library'
 import * as Sharing from 'expo-sharing'
@@ -8,9 +8,9 @@ import {AppBskyGraphDefs, AppBskyGraphStarterpack} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
+import {logEvent} from '#/lib/statsig/statsig'
 import {logger} from '#/logger'
-import {logEvent} from 'lib/statsig/statsig'
-import {isNative, isWeb} from 'platform/detection'
+import {isNative, isWeb} from '#/platform/detection'
 import * as Toast from '#/view/com/util/Toast'
 import {atoms as a} from '#/alf'
 import {Button, ButtonText} from '#/components/Button'
@@ -153,46 +153,54 @@ export function QrCodeDialog({
       <Dialog.ScrollableInner
         label={_(msg`Create a QR code for a starter pack`)}>
         <View style={[a.flex_1, a.align_center, a.gap_5xl]}>
-          {!link ? (
-            <View style={[a.align_center, a.p_xl]}>
-              <Loader size="xl" />
-            </View>
-          ) : (
-            <>
-              <QrCode starterPack={starterPack} link={link} ref={ref} />
-              {isProcessing ? (
-                <View>
-                  <Loader size="xl" />
-                </View>
-              ) : (
-                <View
-                  style={[a.w_full, a.gap_md, isWeb && [a.flex_row_reverse]]}>
-                  <Button
-                    label={_(msg`Copy QR code`)}
-                    variant="solid"
-                    color="secondary"
-                    size="small"
-                    onPress={isWeb ? onCopyPress : onSharePress}>
-                    <ButtonText>
-                      {isWeb ? <Trans>Copy</Trans> : <Trans>Share</Trans>}
-                    </ButtonText>
-                  </Button>
-                  <Button
-                    label={_(msg`Save QR code`)}
-                    variant="solid"
-                    color="secondary"
-                    size="small"
-                    onPress={onSavePress}>
-                    <ButtonText>
-                      <Trans>Save</Trans>
-                    </ButtonText>
-                  </Button>
-                </View>
-              )}
-            </>
-          )}
+          <React.Suspense fallback={<Loading />}>
+            {!link ? (
+              <Loading />
+            ) : (
+              <>
+                <QrCode starterPack={starterPack} link={link} ref={ref} />
+                {isProcessing ? (
+                  <View>
+                    <Loader size="xl" />
+                  </View>
+                ) : (
+                  <View
+                    style={[a.w_full, a.gap_md, isWeb && [a.flex_row_reverse]]}>
+                    <Button
+                      label={_(msg`Copy QR code`)}
+                      variant="solid"
+                      color="secondary"
+                      size="small"
+                      onPress={isWeb ? onCopyPress : onSharePress}>
+                      <ButtonText>
+                        {isWeb ? <Trans>Copy</Trans> : <Trans>Share</Trans>}
+                      </ButtonText>
+                    </Button>
+                    <Button
+                      label={_(msg`Save QR code`)}
+                      variant="solid"
+                      color="secondary"
+                      size="small"
+                      onPress={onSavePress}>
+                      <ButtonText>
+                        <Trans>Save</Trans>
+                      </ButtonText>
+                    </Button>
+                  </View>
+                )}
+              </>
+            )}
+          </React.Suspense>
         </View>
       </Dialog.ScrollableInner>
     </Dialog.Outer>
   )
 }
+
+function Loading() {
+  return (
+    <View style={[a.align_center, a.p_xl]}>
+      <Loader size="xl" />
+    </View>
+  )
+}
diff --git a/src/screens/Onboarding/StepProfile/PlaceholderCanvas.tsx b/src/screens/Onboarding/StepProfile/PlaceholderCanvas.tsx
index d1d1af6d9..eaad2113f 100644
--- a/src/screens/Onboarding/StepProfile/PlaceholderCanvas.tsx
+++ b/src/screens/Onboarding/StepProfile/PlaceholderCanvas.tsx
@@ -1,14 +1,19 @@
 import React from 'react'
 import {View} from 'react-native'
-import ViewShot from 'react-native-view-shot'
+import type ViewShot from 'react-native-view-shot'
 
 import {useAvatar} from '#/screens/Onboarding/StepProfile/index'
 import {atoms as a} from '#/alf'
 
+const LazyViewShot = React.lazy(
+  // @ts-expect-error dynamic import
+  () => import('react-native-view-shot/src/index'),
+)
+
 const SIZE_MULTIPLIER = 5
 
 export interface PlaceholderCanvasRef {
-  capture: () => Promise<string>
+  capture: () => Promise<string | undefined>
 }
 
 // This component is supposed to be invisible to the user. We only need this for ViewShot to have something to
@@ -16,7 +21,7 @@ export interface PlaceholderCanvasRef {
 export const PlaceholderCanvas = React.forwardRef<PlaceholderCanvasRef, {}>(
   function PlaceholderCanvas({}, ref) {
     const {avatar} = useAvatar()
-    const viewshotRef = React.useRef()
+    const viewshotRef = React.useRef<ViewShot>(null)
     const Icon = avatar.placeholder.component
 
     const styles = React.useMemo(
@@ -32,13 +37,16 @@ export const PlaceholderCanvas = React.forwardRef<PlaceholderCanvasRef, {}>(
     )
 
     React.useImperativeHandle(ref, () => ({
-      // @ts-ignore this library doesn't have types
-      capture: viewshotRef.current.capture,
+      capture: async () => {
+        if (viewshotRef.current?.capture) {
+          return await viewshotRef.current.capture()
+        }
+      },
     }))
 
     return (
       <View style={styles.container}>
-        <ViewShot
+        <LazyViewShot
           // @ts-ignore this library doesn't have types
           ref={viewshotRef}
           options={{
@@ -60,7 +68,7 @@ export const PlaceholderCanvas = React.forwardRef<PlaceholderCanvasRef, {}>(
               style={{color: 'white'}}
             />
           </View>
-        </ViewShot>
+        </LazyViewShot>
       </View>
     )
   },
diff --git a/src/screens/Onboarding/StepProfile/index.tsx b/src/screens/Onboarding/StepProfile/index.tsx
index 5304aa503..79957da31 100644
--- a/src/screens/Onboarding/StepProfile/index.tsx
+++ b/src/screens/Onboarding/StepProfile/index.tsx
@@ -10,13 +10,13 @@ import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
 import {useAnalytics} from '#/lib/analytics/analytics'
+import {usePhotoLibraryPermission} from '#/lib/hooks/usePermissions'
+import {compressIfNeeded} from '#/lib/media/manip'
+import {openCropper} from '#/lib/media/picker'
+import {getDataUriSize} from '#/lib/media/util'
+import {useRequestNotificationsPermission} from '#/lib/notifications/notifications'
 import {logEvent, useGate} from '#/lib/statsig/statsig'
-import {usePhotoLibraryPermission} from 'lib/hooks/usePermissions'
-import {compressIfNeeded} from 'lib/media/manip'
-import {openCropper} from 'lib/media/picker'
-import {getDataUriSize} from 'lib/media/util'
-import {useRequestNotificationsPermission} from 'lib/notifications/notifications'
-import {isNative, isWeb} from 'platform/detection'
+import {isNative, isWeb} from '#/platform/detection'
 import {
   DescriptionText,
   OnboardingControls,
@@ -132,6 +132,10 @@ export function StepProfile() {
 
   const onContinue = React.useCallback(async () => {
     let imageUri = avatar?.image?.path
+
+    // In the event that view-shot didn't load in time and the user pressed continue, this will just be undefined
+    // and the default avatar will be used. We don't want to block getting through create if this fails for some
+    // reason
     if (!imageUri || avatar.useCreatedAvatar) {
       imageUri = await canvasRef.current?.capture()
     }
diff --git a/src/screens/Onboarding/state.ts b/src/screens/Onboarding/state.ts
index c41db5c3b..70fa69640 100644
--- a/src/screens/Onboarding/state.ts
+++ b/src/screens/Onboarding/state.ts
@@ -51,13 +51,15 @@ export type OnboardingAction =
   | {
       type: 'setProfileStepResults'
       isCreatedAvatar: boolean
-      image?: OnboardingState['profileStepResults']['image']
-      imageUri: string
+      image: OnboardingState['profileStepResults']['image'] | undefined
+      imageUri: string | undefined
       imageMime: string
-      creatorState?: {
-        emoji: Emoji
-        backgroundColor: AvatarColor
-      }
+      creatorState:
+        | {
+            emoji: Emoji
+            backgroundColor: AvatarColor
+          }
+        | undefined
     }
 
 export type ApiResponseMap = {
diff --git a/src/screens/Signup/StepInfo/index.tsx b/src/screens/Signup/StepInfo/index.tsx
index 2cdb4b722..d9b680602 100644
--- a/src/screens/Signup/StepInfo/index.tsx
+++ b/src/screens/Signup/StepInfo/index.tsx
@@ -6,8 +6,8 @@ import * as EmailValidator from 'email-validator'
 import type tldts from 'tldts'
 
 import {logEvent} from '#/lib/statsig/statsig'
+import {isEmailMaybeInvalid} from '#/lib/strings/email'
 import {logger} from '#/logger'
-import {isEmailMaybeInvalid} from 'lib/strings/email'
 import {ScreenTransition} from '#/screens/Login/ScreenTransition'
 import {is13, is18, useSignupContext} from '#/screens/Signup/state'
 import {Policies} from '#/screens/Signup/StepInfo/Policies'
@@ -59,6 +59,9 @@ export function StepInfo({
     import('tldts/dist/index.cjs.min.js').then(tldts => {
       tldtsRef.current = tldts
     })
+    // This will get used in the avatar creator a few steps later, so lets preload it now
+    // @ts-expect-error - valid path
+    import('react-native-view-shot/src/index')
   }, [])
 
   const onNextPress = () => {