about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Navigation.tsx34
-rw-r--r--src/lib/analytics/types.ts1
-rw-r--r--src/state/models/discovery/onboarding.ts29
-rw-r--r--src/view/com/auth/onboarding/RecommendedFeeds.tsx160
-rw-r--r--src/view/com/auth/onboarding/Welcome.tsx38
-rw-r--r--src/view/index.ts2
6 files changed, 225 insertions, 39 deletions
diff --git a/src/Navigation.tsx b/src/Navigation.tsx
index 6ea92e1d4..058a15fa2 100644
--- a/src/Navigation.tsx
+++ b/src/Navigation.tsx
@@ -67,7 +67,7 @@ import {getRoutingInstrumentation} from 'lib/sentry'
 import {bskyTitle} from 'lib/strings/headings'
 import {JSX} from 'react/jsx-runtime'
 import {timeout} from 'lib/async/timeout'
-import {Welcome} from 'view/com/auth/onboarding/Welcome'
+import {Welcome, WelcomeHeaderRight} from 'view/com/auth/onboarding/Welcome'
 import {RecommendedFeeds} from 'view/com/auth/onboarding/RecommendedFeeds'
 
 const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
@@ -221,18 +221,26 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
         component={SavedFeeds}
         options={{title: title('Edit My Feeds')}}
       />
-      <Stack.Group
-        screenOptions={{
-          animation: 'slide_from_bottom',
-          presentation: 'modal',
-        }}>
-        <Stack.Screen
-          name="Welcome"
-          component={Welcome}
-          options={{title: title('Welcome')}}
-        />
-        <Stack.Screen name="RecommendedFeeds" component={RecommendedFeeds} />
-      </Stack.Group>
+      <Stack.Screen
+        name="Welcome"
+        component={Welcome}
+        options={{
+          title: title('Welcome'),
+          presentation: 'card',
+          headerShown: true,
+          headerTransparent: true,
+          headerTitle: '',
+          headerBackVisible: false,
+          headerRight: props => <WelcomeHeaderRight {...props} />,
+        }}
+      />
+      <Stack.Screen
+        name="RecommendedFeeds"
+        component={RecommendedFeeds}
+        options={{
+          title: title('Recommended Feeds'),
+        }}
+      />
     </>
   )
 }
diff --git a/src/lib/analytics/types.ts b/src/lib/analytics/types.ts
index f876c6d53..d56e1b615 100644
--- a/src/lib/analytics/types.ts
+++ b/src/lib/analytics/types.ts
@@ -122,6 +122,7 @@ interface TrackPropertiesMap {
   // ONBOARDING events
   'Onboarding:Begin': {}
   'Onboarding:Complete': {}
+  'Onboarding:Skipped': {}
 }
 
 interface ScreenPropertiesMap {
diff --git a/src/state/models/discovery/onboarding.ts b/src/state/models/discovery/onboarding.ts
index 8e7a0a7b9..52521f578 100644
--- a/src/state/models/discovery/onboarding.ts
+++ b/src/state/models/discovery/onboarding.ts
@@ -1,12 +1,12 @@
 import {makeAutoObservable} from 'mobx'
 import {RootStoreModel} from '../root-store'
-import {NavigationProp} from 'lib/routes/types'
 import {hasProp} from 'lib/type-guards'
+import {track} from 'lib/analytics/analytics'
 
 export const OnboardingScreenSteps = {
   Welcome: 'Welcome',
   RecommendedFeeds: 'RecommendedFeeds',
-  Complete: 'Complete',
+  Home: 'Home',
 } as const
 
 type OnboardingStep =
@@ -34,6 +34,7 @@ export class OnboardingModel {
         typeof v.step === 'string' &&
         OnboardingStepsArray.includes(v.step as OnboardingStep)
       ) {
+        console.log('hydrating onboarding', v.step)
         this.step = v.step as OnboardingStep
       }
     }
@@ -41,31 +42,33 @@ export class OnboardingModel {
     this.reset()
   }
 
-  nextScreenName() {
-    if (this.step === 'Welcome') {
+  nextScreenName(currentScreenName?: OnboardingStep) {
+    if (currentScreenName === 'Welcome' || this.step === 'Welcome') {
       this.step = 'RecommendedFeeds'
       return this.step
-    } else if (this.step === 'RecommendedFeeds') {
-      this.step = 'Complete'
+    } else if (
+      this.step === 'RecommendedFeeds' ||
+      currentScreenName === 'RecommendedFeeds'
+    ) {
+      this.step = 'Home'
       return this.step
-    } else if (this.step === 'Complete') {
-      return 'Home'
     } else {
       // if we get here, we're in an invalid state, let's just go Home
       return 'Home'
     }
   }
 
-  complete(navigation: NavigationProp) {
-    navigation.navigate('Home')
-  }
-
   reset() {
     this.step = 'Welcome'
   }
 
+  skip() {
+    track('Onboarding:Skipped')
+    this.step = 'Home'
+  }
+
   get isComplete() {
-    return this.step === 'Complete'
+    return this.step === 'Home'
   }
 
   get isRemaining() {
diff --git a/src/view/com/auth/onboarding/RecommendedFeeds.tsx b/src/view/com/auth/onboarding/RecommendedFeeds.tsx
index 1936f4234..88fb200c6 100644
--- a/src/view/com/auth/onboarding/RecommendedFeeds.tsx
+++ b/src/view/com/auth/onboarding/RecommendedFeeds.tsx
@@ -1,5 +1,5 @@
 import React from 'react'
-import {StyleSheet, View} from 'react-native'
+import {FlatList, StyleSheet, View} from 'react-native'
 import {Text} from 'view/com/util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
 import {Button} from 'view/com/util/forms/Button'
@@ -7,6 +7,117 @@ import {NativeStackScreenProps} from '@react-navigation/native-stack'
 import {HomeTabNavigatorParams} from 'lib/routes/types'
 import {useStores} from 'state/index'
 import {observer} from 'mobx-react-lite'
+import {CustomFeed} from 'view/com/feeds/CustomFeed'
+import {useCustomFeed} from 'lib/hooks/useCustomFeed'
+import {makeRecordUri} from 'lib/strings/url-helpers'
+import {ViewHeader} from 'view/com/util/ViewHeader'
+
+const TEMPORARY_RECOMMENDED_FEEDS = [
+  {
+    did: 'did:plc:hsqwcidfez66lwm3gxhfv5in',
+    rkey: 'aaaf2pqeodmpy',
+  },
+  {
+    did: 'did:plc:gekdk2nd47gkk3utfz2xf7cn',
+    rkey: 'aaap4tbjcfe5y',
+  },
+  {
+    did: 'did:plc:5rw2on4i56btlcajojaxwcat',
+    rkey: 'aaao6g552b33o',
+  },
+  {
+    did: 'did:plc:jfhpnnst6flqway4eaeqzj2a',
+    rkey: 'for-science',
+  },
+  {
+    did: 'did:plc:7q4nnnxawajbfaq7to5dpbsy',
+    rkey: 'bsky-news',
+  },
+  {
+    did: 'did:plc:jcoy7v3a2t4rcfdh6i4kza25',
+    rkey: 'astro',
+  },
+  {
+    did: 'did:plc:tenurhgjptubkk5zf5qhi3og',
+    rkey: 'h-nba',
+  },
+  {
+    did: 'did:plc:vpkhqolt662uhesyj6nxm7ys',
+    rkey: 'devfeed',
+  },
+  {
+    did: 'did:plc:cndfx4udwgvpjaakvxvh7wm5',
+    rkey: 'flipboard-tech',
+  },
+  {
+    did: 'did:plc:w4xbfzo7kqfes5zb7r6qv3rw',
+    rkey: 'blacksky',
+  },
+  {
+    did: 'did:plc:lptjvw6ut224kwrj7ub3sqbe',
+    rkey: 'aaaotfjzjplna',
+  },
+  {
+    did: 'did:plc:gkvpokm7ec5j5yxls6xk4e3z',
+    rkey: 'formula-one',
+  },
+  {
+    did: 'did:plc:q6gjnaw2blty4crticxkmujt',
+    rkey: 'positivifeed',
+  },
+  {
+    did: 'did:plc:l72uci4styb4jucsgcrrj5ap',
+    rkey: 'aaao5dzfm36u4',
+  },
+  {
+    did: 'did:plc:k3jkadxv5kkjgs6boyon7m6n',
+    rkey: 'aaaavlyvqzst2',
+  },
+  {
+    did: 'did:plc:nkahctfdi6bxk72umytfwghw',
+    rkey: 'aaado2uvfsc6w',
+  },
+  {
+    did: 'did:plc:epihigio3d7un7u3gpqiy5gv',
+    rkey: 'aaaekwsc7zsvs',
+  },
+  {
+    did: 'did:plc:qiknc4t5rq7yngvz7g4aezq7',
+    rkey: 'aaaejxlobe474',
+  },
+  {
+    did: 'did:plc:mlq4aycufcuolr7ax6sezpc4',
+    rkey: 'aaaoudweck6uy',
+  },
+  {
+    did: 'did:plc:rcez5hcvq3vzlu5x7xrjyccg',
+    rkey: 'aaadzjxbcddzi',
+  },
+  {
+    did: 'did:plc:lnxbuzaenlwjrncx6sc4cfdr',
+    rkey: 'aaab2vesjtszc',
+  },
+  {
+    did: 'did:plc:x3cya3wkt4n6u4ihmvpsc5if',
+    rkey: 'aaacynbxwimok',
+  },
+  {
+    did: 'did:plc:abv47bjgzjgoh3yrygwoi36x',
+    rkey: 'aaagt6amuur5e',
+  },
+  {
+    did: 'did:plc:ffkgesg3jsv2j7aagkzrtcvt',
+    rkey: 'aaacjerk7gwek',
+  },
+  {
+    did: 'did:plc:geoqe3qls5mwezckxxsewys2',
+    rkey: 'aaai43yetqshu',
+  },
+  {
+    did: 'did:plc:2wqomm3tjqbgktbrfwgvrw34',
+    rkey: 'authors',
+  },
+]
 
 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'RecommendedFeeds'>
 export const RecommendedFeeds = observer(({navigation}: Props) => {
@@ -14,41 +125,68 @@ export const RecommendedFeeds = observer(({navigation}: Props) => {
   const store = useStores()
 
   const next = () => {
-    const nextScreenName = store.onboarding.nextScreenName()
+    const nextScreenName = store.onboarding.nextScreenName('RecommendedFeeds')
     if (nextScreenName) {
       navigation.navigate(nextScreenName)
     }
   }
 
   return (
-    <View style={[styles.container]}>
-      <View testID="recommendedFeedsScreen">
-        <Text type="lg-bold" style={[pal.text]}>
-          Check out some recommended feeds. Click + to add them to your list of
-          pinned feeds.
-        </Text>
-      </View>
+    <View style={[styles.container]} testID="recommendedFeedsScreen">
+      <ViewHeader title="Recommended Feeds" canGoBack />
+      <Text type="lg-medium" style={[pal.text, styles.header]}>
+        Check out some recommended feeds. Click + to add them to your list of
+        pinned feeds.
+      </Text>
+
+      <FlatList
+        data={TEMPORARY_RECOMMENDED_FEEDS}
+        renderItem={({item}) => <Item item={item} />}
+        keyExtractor={item => item.did + item.rkey}
+        style={{flex: 1}}
+      />
 
       <Button
         onPress={next}
         label="Continue"
         testID="continueBtn"
+        style={styles.button}
         labelStyle={styles.buttonText}
       />
     </View>
   )
 })
 
+type ItemProps = {
+  did: string
+  rkey: string
+}
+
+const Item = ({item}: {item: ItemProps}) => {
+  const uri = makeRecordUri(item.did, 'app.bsky.feed.generator', item.rkey)
+  const data = useCustomFeed(uri)
+  if (!data) return null
+  return (
+    <CustomFeed item={data} key={uri} showDescription showLikes showSaveBtn />
+  )
+}
+
 const styles = StyleSheet.create({
   container: {
     flex: 1,
-    marginVertical: 60,
     marginHorizontal: 16,
     justifyContent: 'space-between',
   },
+  header: {
+    marginBottom: 16,
+  },
+  button: {
+    marginBottom: 48,
+    marginTop: 16,
+  },
   buttonText: {
     textAlign: 'center',
     fontSize: 18,
-    marginVertical: 4,
+    paddingVertical: 4,
   },
 })
diff --git a/src/view/com/auth/onboarding/Welcome.tsx b/src/view/com/auth/onboarding/Welcome.tsx
index 5b663fe16..cb3a2307a 100644
--- a/src/view/com/auth/onboarding/Welcome.tsx
+++ b/src/view/com/auth/onboarding/Welcome.tsx
@@ -1,5 +1,5 @@
 import React from 'react'
-import {StyleSheet, View} from 'react-native'
+import {Pressable, StyleSheet, View} from 'react-native'
 import {Text} from 'view/com/util/text/Text'
 import {s} from 'lib/styles'
 import {usePalette} from 'lib/hooks/usePalette'
@@ -9,14 +9,23 @@ import {NativeStackScreenProps} from '@react-navigation/native-stack'
 import {HomeTabNavigatorParams} from 'lib/routes/types'
 import {useStores} from 'state/index'
 import {observer} from 'mobx-react-lite'
+import {HeaderButtonProps} from '@react-navigation/native-stack/lib/typescript/src/types'
+import {NavigationProp, useNavigation} from '@react-navigation/native'
 
 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Welcome'>
 export const Welcome = observer(({navigation}: Props) => {
   const pal = usePalette('default')
   const store = useStores()
 
+  // make sure bottom nav is hidden
+  React.useEffect(() => {
+    if (!store.shell.minimalShellMode) {
+      store.shell.setMinimalShellMode(true)
+    }
+  }, [store.shell.minimalShellMode, store])
+
   const next = () => {
-    const nextScreenName = store.onboarding.nextScreenName()
+    const nextScreenName = store.onboarding.nextScreenName('Welcome')
     if (nextScreenName) {
       navigation.navigate(nextScreenName)
     }
@@ -76,6 +85,31 @@ export const Welcome = observer(({navigation}: Props) => {
   )
 })
 
+export const WelcomeHeaderRight = (props: HeaderButtonProps) => {
+  const {canGoBack} = props
+  const pal = usePalette('default')
+  const navigation = useNavigation<NavigationProp<HomeTabNavigatorParams>>()
+  const store = useStores()
+  return (
+    <Pressable
+      accessibilityRole="button"
+      style={[s.flexRow, s.alignCenter]}
+      onPress={() => {
+        if (canGoBack) {
+          store.onboarding.skip()
+          navigation.goBack()
+        }
+      }}>
+      <Text style={[pal.link]}>Skip</Text>
+      <FontAwesomeIcon
+        icon={'chevron-right'}
+        size={14}
+        color={pal.colors.link}
+      />
+    </Pressable>
+  )
+}
+
 const styles = StyleSheet.create({
   container: {
     flex: 1,
diff --git a/src/view/index.ts b/src/view/index.ts
index 1c3dc3937..2e4c08ec7 100644
--- a/src/view/index.ts
+++ b/src/view/index.ts
@@ -92,6 +92,7 @@ import {faPlay} from '@fortawesome/free-solid-svg-icons/faPlay'
 import {faPause} from '@fortawesome/free-solid-svg-icons/faPause'
 import {faThumbtack} from '@fortawesome/free-solid-svg-icons/faThumbtack'
 import {faList} from '@fortawesome/free-solid-svg-icons/faList'
+import {faChevronRight} from '@fortawesome/free-solid-svg-icons/faChevronRight'
 
 export function setup() {
   library.add(
@@ -187,5 +188,6 @@ export function setup() {
     faPlay,
     faPause,
     faList,
+    faChevronRight,
   )
 }