about summary refs log tree commit diff
path: root/src/view/screens
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/screens')
-rw-r--r--src/view/screens/Composer.tsx43
-rw-r--r--src/view/screens/Home.tsx65
-rw-r--r--src/view/screens/Login.tsx (renamed from src/view/screens/tabroots/Login.tsx)12
-rw-r--r--src/view/screens/NotFound.tsx13
-rw-r--r--src/view/screens/Notifications.tsx65
-rw-r--r--src/view/screens/PostLikedBy.tsx26
-rw-r--r--src/view/screens/PostRepostedBy.tsx26
-rw-r--r--src/view/screens/PostThread.tsx32
-rw-r--r--src/view/screens/Profile.tsx58
-rw-r--r--src/view/screens/ProfileFollowers.tsx24
-rw-r--r--src/view/screens/ProfileFollows.tsx24
-rw-r--r--src/view/screens/Search.tsx11
-rw-r--r--src/view/screens/Signup.tsx (renamed from src/view/screens/tabroots/Signup.tsx)12
-rw-r--r--src/view/screens/stacks/Composer.tsx50
-rw-r--r--src/view/screens/stacks/PostLikedBy.tsx38
-rw-r--r--src/view/screens/stacks/PostRepostedBy.tsx41
-rw-r--r--src/view/screens/stacks/PostThread.tsx38
-rw-r--r--src/view/screens/stacks/Profile.tsx71
-rw-r--r--src/view/screens/stacks/ProfileFollowers.tsx39
-rw-r--r--src/view/screens/stacks/ProfileFollows.tsx39
-rw-r--r--src/view/screens/tabroots/Home.tsx69
-rw-r--r--src/view/screens/tabroots/Menu.tsx16
-rw-r--r--src/view/screens/tabroots/NotFound.tsx15
-rw-r--r--src/view/screens/tabroots/Notifications.tsx71
-rw-r--r--src/view/screens/tabroots/Search.tsx14
25 files changed, 395 insertions, 517 deletions
diff --git a/src/view/screens/Composer.tsx b/src/view/screens/Composer.tsx
new file mode 100644
index 000000000..2de84583f
--- /dev/null
+++ b/src/view/screens/Composer.tsx
@@ -0,0 +1,43 @@
+import React, {useLayoutEffect, useRef} from 'react'
+// import {Text, TouchableOpacity} from 'react-native'
+// import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {Composer as ComposerComponent} from '../com/composer/Composer'
+import {ScreenParams} from '../routes'
+
+export const Composer = ({params}: ScreenParams) => {
+  const {replyTo} = params
+  const ref = useRef<{publish: () => Promise<boolean>}>()
+
+  // TODO
+  // useLayoutEffect(() => {
+  //   navigation.setOptions({
+  //     headerShown: true,
+  //     headerTitle: replyTo ? 'Reply' : 'New Post',
+  //     headerLeft: () => (
+  //       <TouchableOpacity onPress={() => navigation.goBack()}>
+  //         <FontAwesomeIcon icon="x" />
+  //       </TouchableOpacity>
+  //     ),
+  //     headerRight: () => (
+  //       <TouchableOpacity
+  //         onPress={() => {
+  //           if (!ref.current) {
+  //             return
+  //           }
+  //           ref.current.publish().then(
+  //             posted => {
+  //               if (posted) {
+  //                 navigation.goBack()
+  //               }
+  //             },
+  //             err => console.error('Failed to create post', err),
+  //           )
+  //         }}>
+  //         <Text>Post</Text>
+  //       </TouchableOpacity>
+  //     ),
+  //   })
+  // }, [navigation, replyTo, ref])
+
+  return <ComposerComponent ref={ref} replyTo={replyTo} />
+}
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
new file mode 100644
index 000000000..a94ffd2f7
--- /dev/null
+++ b/src/view/screens/Home.tsx
@@ -0,0 +1,65 @@
+import React, {useState, useEffect, useLayoutEffect} from 'react'
+import {Image, StyleSheet, TouchableOpacity, View} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {Feed} from '../com/feed/Feed'
+import {useStores} from '../../state'
+import {useLoadEffect} from '../lib/navigation'
+import {AVIS} from '../lib/assets'
+import {ScreenParams} from '../routes'
+
+export function Home({params}: ScreenParams) {
+  const [hasSetup, setHasSetup] = useState<boolean>(false)
+  const store = useStores()
+  useLoadEffect(() => {
+    store.nav.setTitle('Home')
+    console.log('Fetching home feed')
+    store.homeFeed.setup().then(() => setHasSetup(true))
+  }, [store.nav, store.homeFeed])
+
+  // TODO
+  // useEffect(() => {
+  //   return navigation.addListener('focus', () => {
+  //     if (hasSetup) {
+  //       console.log('Updating home feed')
+  //       store.homeFeed.update()
+  //     }
+  //   })
+  // }, [navigation, store.homeFeed, hasSetup])
+
+  // TODO
+  // useLayoutEffect(() => {
+  //   navigation.setOptions({
+  //     headerShown: true,
+  //     headerTitle: 'V I B E',
+  //     headerLeft: () => (
+  //       <TouchableOpacity
+  //         onPress={() => navigation.push('Profile', {name: 'alice.com'})}>
+  //         <Image source={AVIS['alice.com']} style={styles.avi} />
+  //       </TouchableOpacity>
+  //     ),
+  //     headerRight: () => (
+  //       <TouchableOpacity
+  //         onPress={() => {
+  //           navigation.push('Composer', {})
+  //         }}>
+  //         <FontAwesomeIcon icon="plus" style={{color: '#006bf7'}} />
+  //       </TouchableOpacity>
+  //     ),
+  //   })
+  // }, [navigation])
+
+  return (
+    <View>
+      <Feed feed={store.homeFeed} />
+    </View>
+  )
+}
+
+const styles = StyleSheet.create({
+  avi: {
+    width: 20,
+    height: 20,
+    borderRadius: 10,
+    resizeMode: 'cover',
+  },
+})
diff --git a/src/view/screens/tabroots/Login.tsx b/src/view/screens/Login.tsx
index a5f670bdd..0857687ab 100644
--- a/src/view/screens/tabroots/Login.tsx
+++ b/src/view/screens/Login.tsx
@@ -1,18 +1,15 @@
 import React from 'react'
 import {Text, View} from 'react-native'
 import {observer} from 'mobx-react-lite'
-import {Shell} from '../../shell'
-// import type {RootTabsScreenProps} from '../routes/types'
 // import {useStores} from '../../state'
 
 export const Login = observer(
   (/*{navigation}: RootTabsScreenProps<'Login'>*/) => {
     // const store = useStores()
     return (
-      <Shell>
-        <View style={{justifyContent: 'center', alignItems: 'center'}}>
-          <Text style={{fontSize: 20, fontWeight: 'bold'}}>Sign In</Text>
-          {/*store.session.uiError && <Text>{store.session.uiError}</Text>}
+      <View style={{justifyContent: 'center', alignItems: 'center'}}>
+        <Text style={{fontSize: 20, fontWeight: 'bold'}}>Sign In</Text>
+        {/*store.session.uiError && <Text>{store.session.uiError}</Text>}
         {!store.session.uiIsProcessing ? (
           <>
             <Button title="Login" onPress={() => store.session.login()} />
@@ -24,8 +21,7 @@ export const Login = observer(
         ) : (
           <ActivityIndicator />
         )*/}
-        </View>
-      </Shell>
+      </View>
     )
   },
 )
diff --git a/src/view/screens/NotFound.tsx b/src/view/screens/NotFound.tsx
new file mode 100644
index 000000000..2483da1e6
--- /dev/null
+++ b/src/view/screens/NotFound.tsx
@@ -0,0 +1,13 @@
+import React from 'react'
+import {Text, Button, View} from 'react-native'
+import {useStores} from '../../state'
+
+export const NotFound = () => {
+  const stores = useStores()
+  return (
+    <View style={{justifyContent: 'center', alignItems: 'center'}}>
+      <Text style={{fontSize: 20, fontWeight: 'bold'}}>Page not found</Text>
+      <Button title="Home" onPress={() => stores.nav.navigate('/')} />
+    </View>
+  )
+}
diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx
new file mode 100644
index 000000000..7ebc8a7ce
--- /dev/null
+++ b/src/view/screens/Notifications.tsx
@@ -0,0 +1,65 @@
+import React, {useState, useEffect, useLayoutEffect} from 'react'
+import {Image, StyleSheet, TouchableOpacity, View} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {Feed} from '../com/notifications/Feed'
+import {useStores} from '../../state'
+import {AVIS} from '../lib/assets'
+import {ScreenParams} from '../routes'
+import {useLoadEffect} from '../lib/navigation'
+
+export const Notifications = ({params}: ScreenParams) => {
+  const [hasSetup, setHasSetup] = useState<boolean>(false)
+  const store = useStores()
+  useLoadEffect(() => {
+    store.nav.setTitle('Notifications')
+    console.log('Fetching notifications feed')
+    store.notesFeed.setup().then(() => setHasSetup(true))
+  }, [store.notesFeed])
+
+  // TODO
+  // useEffect(() => {
+  //   return navigation.addListener('focus', () => {
+  //     if (hasSetup) {
+  //       console.log('Updating notifications feed')
+  //       store.notesFeed.update()
+  //     }
+  //   })
+  // }, [navigation, store.notesFeed, hasSetup])
+
+  // TODO
+  // useLayoutEffect(() => {
+  //   navigation.setOptions({
+  //     headerShown: true,
+  //     headerTitle: 'Notifications',
+  //     headerLeft: () => (
+  //       <TouchableOpacity
+  //         onPress={() => navigation.push('Profile', {name: 'alice.com'})}>
+  //         <Image source={AVIS['alice.com']} style={styles.avi} />
+  //       </TouchableOpacity>
+  //     ),
+  //     headerRight: () => (
+  //       <TouchableOpacity
+  //         onPress={() => {
+  //           navigation.push('Composer', {})
+  //         }}>
+  //         <FontAwesomeIcon icon="plus" style={{color: '#006bf7'}} />
+  //       </TouchableOpacity>
+  //     ),
+  //   })
+  // }, [navigation])
+
+  return (
+    <View>
+      <Feed view={store.notesFeed} />
+    </View>
+  )
+}
+
+const styles = StyleSheet.create({
+  avi: {
+    width: 20,
+    height: 20,
+    borderRadius: 10,
+    resizeMode: 'cover',
+  },
+})
diff --git a/src/view/screens/PostLikedBy.tsx b/src/view/screens/PostLikedBy.tsx
new file mode 100644
index 000000000..92fae30ad
--- /dev/null
+++ b/src/view/screens/PostLikedBy.tsx
@@ -0,0 +1,26 @@
+import React, {useLayoutEffect} from 'react'
+import {TouchableOpacity} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {makeRecordUri} from '../lib/strings'
+import {PostLikedBy as PostLikedByComponent} from '../com/post-thread/PostLikedBy'
+import {ScreenParams} from '../routes'
+
+export const PostLikedBy = ({params}: ScreenParams) => {
+  const {name, recordKey} = params
+  const uri = makeRecordUri(name, 'blueskyweb.xyz:Posts', recordKey)
+
+  // TODO
+  // useLayoutEffect(() => {
+  //   navigation.setOptions({
+  //     headerShown: true,
+  //     headerTitle: 'Liked By',
+  //     headerLeft: () => (
+  //       <TouchableOpacity onPress={() => navigation.goBack()}>
+  //         <FontAwesomeIcon icon="arrow-left" />
+  //       </TouchableOpacity>
+  //     ),
+  //   })
+  // }, [navigation])
+
+  return <PostLikedByComponent uri={uri} />
+}
diff --git a/src/view/screens/PostRepostedBy.tsx b/src/view/screens/PostRepostedBy.tsx
new file mode 100644
index 000000000..81014a7c7
--- /dev/null
+++ b/src/view/screens/PostRepostedBy.tsx
@@ -0,0 +1,26 @@
+import React, {useLayoutEffect} from 'react'
+import {TouchableOpacity} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {makeRecordUri} from '../lib/strings'
+import {PostRepostedBy as PostRepostedByComponent} from '../com/post-thread/PostRepostedBy'
+import {ScreenParams} from '../routes'
+
+export const PostRepostedBy = ({params}: ScreenParams) => {
+  const {name, recordKey} = params
+  const uri = makeRecordUri(name, 'blueskyweb.xyz:Posts', recordKey)
+
+  // TODO
+  // useLayoutEffect(() => {
+  //   navigation.setOptions({
+  //     headerShown: true,
+  //     headerTitle: 'Reposted By',
+  //     headerLeft: () => (
+  //       <TouchableOpacity onPress={() => navigation.goBack()}>
+  //         <FontAwesomeIcon icon="arrow-left" />
+  //       </TouchableOpacity>
+  //     ),
+  //   })
+  // }, [navigation])
+
+  return <PostRepostedByComponent uri={uri} />
+}
diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx
new file mode 100644
index 000000000..1003a40e1
--- /dev/null
+++ b/src/view/screens/PostThread.tsx
@@ -0,0 +1,32 @@
+import React, {useEffect, useLayoutEffect} from 'react'
+import {TouchableOpacity} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {makeRecordUri} from '../lib/strings'
+import {PostThread as PostThreadComponent} from '../com/post-thread/PostThread'
+import {ScreenParams} from '../routes'
+import {useStores} from '../../state'
+import {useLoadEffect} from '../lib/navigation'
+
+export const PostThread = ({params}: ScreenParams) => {
+  const store = useStores()
+  const {name, recordKey} = params
+  const uri = makeRecordUri(name, 'blueskyweb.xyz:Posts', recordKey)
+  useLoadEffect(() => {
+    store.nav.setTitle(`Post by ${name}`)
+  }, [store.nav, name])
+
+  // TODO
+  // useLayoutEffect(() => {
+  //   navigation.setOptions({
+  //     headerShown: true,
+  //     headerTitle: 'Thread',
+  //     headerLeft: () => (
+  //       <TouchableOpacity onPress={() => navigation.goBack()}>
+  //         <FontAwesomeIcon icon="arrow-left" />
+  //       </TouchableOpacity>
+  //     ),
+  //   })
+  // }, [navigation])
+
+  return <PostThreadComponent uri={uri} />
+}
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
new file mode 100644
index 000000000..84ff63f5a
--- /dev/null
+++ b/src/view/screens/Profile.tsx
@@ -0,0 +1,58 @@
+import React, {useState, useEffect} from 'react'
+import {View, StyleSheet} from 'react-native'
+import {FeedViewModel} from '../../state/models/feed-view'
+import {useStores} from '../../state'
+import {ProfileHeader} from '../com/profile/ProfileHeader'
+import {Feed} from '../com/feed/Feed'
+import {ScreenParams} from '../routes'
+import {useLoadEffect} from '../lib/navigation'
+
+export const Profile = ({params}: ScreenParams) => {
+  const store = useStores()
+  const [hasSetup, setHasSetup] = useState<string>('')
+  const [feedView, setFeedView] = useState<FeedViewModel | undefined>()
+
+  useLoadEffect(() => {
+    const author = params.name
+    if (feedView?.params.author === author) {
+      return // no change needed? or trigger refresh?
+    }
+    console.log('Fetching profile feed', author)
+    const newFeedView = new FeedViewModel(store, {author})
+    setFeedView(newFeedView)
+    newFeedView
+      .setup()
+      .catch(err => console.error('Failed to fetch feed', err))
+      .then(() => {
+        setHasSetup(author)
+        store.nav.setTitle(author)
+      })
+  }, [params.name, feedView?.params.author, store])
+
+  // TODO
+  // useEffect(() => {
+  //   return navigation.addListener('focus', () => {
+  //     if (hasSetup === feedView?.params.author) {
+  //       console.log('Updating profile feed', hasSetup)
+  //       feedView?.update()
+  //     }
+  //   })
+  // }, [navigation, feedView, hasSetup])
+
+  return (
+    <View style={styles.container}>
+      <ProfileHeader user={params.name} />
+      <View style={styles.feed}>{feedView && <Feed feed={feedView} />}</View>
+    </View>
+  )
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flexDirection: 'column',
+    height: '100%',
+  },
+  feed: {
+    flex: 1,
+  },
+})
diff --git a/src/view/screens/ProfileFollowers.tsx b/src/view/screens/ProfileFollowers.tsx
new file mode 100644
index 000000000..c8e752685
--- /dev/null
+++ b/src/view/screens/ProfileFollowers.tsx
@@ -0,0 +1,24 @@
+import React, {useLayoutEffect} from 'react'
+import {TouchableOpacity} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {ProfileFollowers as ProfileFollowersComponent} from '../com/profile/ProfileFollowers'
+import {ScreenParams} from '../routes'
+
+export const ProfileFollowers = ({params}: ScreenParams) => {
+  const {name} = params
+
+  // TODO
+  // useLayoutEffect(() => {
+  //   navigation.setOptions({
+  //     headerShown: true,
+  //     headerTitle: 'Followers',
+  //     headerLeft: () => (
+  //       <TouchableOpacity onPress={() => navigation.goBack()}>
+  //         <FontAwesomeIcon icon="arrow-left" />
+  //       </TouchableOpacity>
+  //     ),
+  //   })
+  // }, [navigation])
+
+  return <ProfileFollowersComponent name={name} />
+}
diff --git a/src/view/screens/ProfileFollows.tsx b/src/view/screens/ProfileFollows.tsx
new file mode 100644
index 000000000..96ce60ddd
--- /dev/null
+++ b/src/view/screens/ProfileFollows.tsx
@@ -0,0 +1,24 @@
+import React, {useLayoutEffect} from 'react'
+import {TouchableOpacity} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {ProfileFollows as ProfileFollowsComponent} from '../com/profile/ProfileFollows'
+import {ScreenParams} from '../routes'
+
+export const ProfileFollows = ({params}: ScreenParams) => {
+  const {name} = params
+
+  // TODO
+  // useLayoutEffect(() => {
+  //   navigation.setOptions({
+  //     headerShown: true,
+  //     headerTitle: 'Following',
+  //     headerLeft: () => (
+  //       <TouchableOpacity onPress={() => navigation.goBack()}>
+  //         <FontAwesomeIcon icon="arrow-left" />
+  //       </TouchableOpacity>
+  //     ),
+  //   })
+  // }, [navigation])
+
+  return <ProfileFollowsComponent name={name} />
+}
diff --git a/src/view/screens/Search.tsx b/src/view/screens/Search.tsx
new file mode 100644
index 000000000..aea54051e
--- /dev/null
+++ b/src/view/screens/Search.tsx
@@ -0,0 +1,11 @@
+import React from 'react'
+import {Text, View} from 'react-native'
+import {ScreenParams} from '../routes'
+
+export const Search = ({params}: ScreenParams) => {
+  return (
+    <View style={{justifyContent: 'center', alignItems: 'center'}}>
+      <Text style={{fontSize: 20, fontWeight: 'bold'}}>Search</Text>
+    </View>
+  )
+}
diff --git a/src/view/screens/tabroots/Signup.tsx b/src/view/screens/Signup.tsx
index dc2af2b1e..a34cd5727 100644
--- a/src/view/screens/tabroots/Signup.tsx
+++ b/src/view/screens/Signup.tsx
@@ -1,18 +1,15 @@
 import React from 'react'
 import {Text, View} from 'react-native'
 import {observer} from 'mobx-react-lite'
-import {Shell} from '../../shell'
-// import type {RootTabsScreenProps} from '../routes/types'
 // import {useStores} from '../../state'
 
 export const Signup = observer(
   (/*{navigation}: RootTabsScreenProps<'Signup'>*/) => {
     // const store = useStores()
     return (
-      <Shell>
-        <View style={{justifyContent: 'center', alignItems: 'center'}}>
-          <Text style={{fontSize: 20, fontWeight: 'bold'}}>Create Account</Text>
-          {/*store.session.uiError ?? <Text>{store.session.uiError}</Text>}
+      <View style={{justifyContent: 'center', alignItems: 'center'}}>
+        <Text style={{fontSize: 20, fontWeight: 'bold'}}>Create Account</Text>
+        {/*store.session.uiError ?? <Text>{store.session.uiError}</Text>}
           {!store.session.uiIsProcessing ? (
             <>
               <Button
@@ -27,8 +24,7 @@ export const Signup = observer(
           ) : (
             <ActivityIndicator />
           )*/}
-        </View>
-      </Shell>
+      </View>
     )
   },
 )
diff --git a/src/view/screens/stacks/Composer.tsx b/src/view/screens/stacks/Composer.tsx
deleted file mode 100644
index e1b36567a..000000000
--- a/src/view/screens/stacks/Composer.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import React, {useLayoutEffect, useRef} from 'react'
-import {Text, TouchableOpacity} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {Shell} from '../../shell'
-import type {RootTabsScreenProps} from '../../routes/types'
-import {Composer as ComposerComponent} from '../../com/composer/Composer'
-
-export const Composer = ({
-  navigation,
-  route,
-}: RootTabsScreenProps<'Composer'>) => {
-  const {replyTo} = route.params
-  const ref = useRef<{publish: () => Promise<boolean>}>()
-
-  useLayoutEffect(() => {
-    navigation.setOptions({
-      headerShown: true,
-      headerTitle: replyTo ? 'Reply' : 'New Post',
-      headerLeft: () => (
-        <TouchableOpacity onPress={() => navigation.goBack()}>
-          <FontAwesomeIcon icon="x" />
-        </TouchableOpacity>
-      ),
-      headerRight: () => (
-        <TouchableOpacity
-          onPress={() => {
-            if (!ref.current) {
-              return
-            }
-            ref.current.publish().then(
-              posted => {
-                if (posted) {
-                  navigation.goBack()
-                }
-              },
-              err => console.error('Failed to create post', err),
-            )
-          }}>
-          <Text>Post</Text>
-        </TouchableOpacity>
-      ),
-    })
-  }, [navigation, replyTo, ref])
-
-  return (
-    <Shell>
-      <ComposerComponent ref={ref} replyTo={replyTo} />
-    </Shell>
-  )
-}
diff --git a/src/view/screens/stacks/PostLikedBy.tsx b/src/view/screens/stacks/PostLikedBy.tsx
deleted file mode 100644
index f12990141..000000000
--- a/src/view/screens/stacks/PostLikedBy.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React, {useLayoutEffect} from 'react'
-import {TouchableOpacity} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {makeRecordUri} from '../../lib/strings'
-import {Shell} from '../../shell'
-import type {RootTabsScreenProps} from '../../routes/types'
-import {PostLikedBy as PostLikedByComponent} from '../../com/post-thread/PostLikedBy'
-
-export const PostLikedBy = ({
-  navigation,
-  route,
-}: RootTabsScreenProps<'PostLikedBy'>) => {
-  const {name, recordKey} = route.params
-  const uri = makeRecordUri(name, 'blueskyweb.xyz:Posts', recordKey)
-
-  useLayoutEffect(() => {
-    navigation.setOptions({
-      headerShown: true,
-      headerTitle: 'Liked By',
-      headerLeft: () => (
-        <TouchableOpacity onPress={() => navigation.goBack()}>
-          <FontAwesomeIcon icon="arrow-left" />
-        </TouchableOpacity>
-      ),
-    })
-  }, [navigation])
-
-  const onNavigateContent = (screen: string, props: Record<string, string>) => {
-    // @ts-ignore it's up to the callers to supply correct params -prf
-    navigation.push(screen, props)
-  }
-
-  return (
-    <Shell>
-      <PostLikedByComponent uri={uri} onNavigateContent={onNavigateContent} />
-    </Shell>
-  )
-}
diff --git a/src/view/screens/stacks/PostRepostedBy.tsx b/src/view/screens/stacks/PostRepostedBy.tsx
deleted file mode 100644
index 000c1a7fc..000000000
--- a/src/view/screens/stacks/PostRepostedBy.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import React, {useLayoutEffect} from 'react'
-import {TouchableOpacity} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {makeRecordUri} from '../../lib/strings'
-import {Shell} from '../../shell'
-import type {RootTabsScreenProps} from '../../routes/types'
-import {PostRepostedBy as PostRepostedByComponent} from '../../com/post-thread/PostRepostedBy'
-
-export const PostRepostedBy = ({
-  navigation,
-  route,
-}: RootTabsScreenProps<'PostRepostedBy'>) => {
-  const {name, recordKey} = route.params
-  const uri = makeRecordUri(name, 'blueskyweb.xyz:Posts', recordKey)
-
-  useLayoutEffect(() => {
-    navigation.setOptions({
-      headerShown: true,
-      headerTitle: 'Reposted By',
-      headerLeft: () => (
-        <TouchableOpacity onPress={() => navigation.goBack()}>
-          <FontAwesomeIcon icon="arrow-left" />
-        </TouchableOpacity>
-      ),
-    })
-  }, [navigation])
-
-  const onNavigateContent = (screen: string, props: Record<string, string>) => {
-    // @ts-ignore it's up to the callers to supply correct params -prf
-    navigation.push(screen, props)
-  }
-
-  return (
-    <Shell>
-      <PostRepostedByComponent
-        uri={uri}
-        onNavigateContent={onNavigateContent}
-      />
-    </Shell>
-  )
-}
diff --git a/src/view/screens/stacks/PostThread.tsx b/src/view/screens/stacks/PostThread.tsx
deleted file mode 100644
index 485a2e49a..000000000
--- a/src/view/screens/stacks/PostThread.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React, {useLayoutEffect} from 'react'
-import {TouchableOpacity} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {makeRecordUri} from '../../lib/strings'
-import {Shell} from '../../shell'
-import type {RootTabsScreenProps} from '../../routes/types'
-import {PostThread as PostThreadComponent} from '../../com/post-thread/PostThread'
-
-export const PostThread = ({
-  navigation,
-  route,
-}: RootTabsScreenProps<'PostThread'>) => {
-  const {name, recordKey} = route.params
-  const uri = makeRecordUri(name, 'blueskyweb.xyz:Posts', recordKey)
-
-  useLayoutEffect(() => {
-    navigation.setOptions({
-      headerShown: true,
-      headerTitle: 'Thread',
-      headerLeft: () => (
-        <TouchableOpacity onPress={() => navigation.goBack()}>
-          <FontAwesomeIcon icon="arrow-left" />
-        </TouchableOpacity>
-      ),
-    })
-  }, [navigation])
-
-  const onNavigateContent = (screen: string, props: Record<string, string>) => {
-    // @ts-ignore it's up to the callers to supply correct params -prf
-    navigation.push(screen, props)
-  }
-
-  return (
-    <Shell>
-      <PostThreadComponent uri={uri} onNavigateContent={onNavigateContent} />
-    </Shell>
-  )
-}
diff --git a/src/view/screens/stacks/Profile.tsx b/src/view/screens/stacks/Profile.tsx
deleted file mode 100644
index d8de12436..000000000
--- a/src/view/screens/stacks/Profile.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import React, {useState, useEffect} from 'react'
-import {View, StyleSheet} from 'react-native'
-import {Shell} from '../../shell'
-import type {RootTabsScreenProps} from '../../routes/types'
-import {FeedViewModel} from '../../../state/models/feed-view'
-import {useStores} from '../../../state'
-import {ProfileHeader} from '../../com/profile/ProfileHeader'
-import {Feed} from '../../com/feed/Feed'
-
-export const Profile = ({
-  navigation,
-  route,
-}: RootTabsScreenProps<'Profile'>) => {
-  const store = useStores()
-  const [hasSetup, setHasSetup] = useState<string>('')
-  const [feedView, setFeedView] = useState<FeedViewModel | undefined>()
-
-  useEffect(() => {
-    const author = route.params.name
-    if (feedView?.params.author === author) {
-      return // no change needed? or trigger refresh?
-    }
-    console.log('Fetching profile feed', author)
-    const newFeedView = new FeedViewModel(store, {author})
-    setFeedView(newFeedView)
-    newFeedView
-      .setup()
-      .catch(err => console.error('Failed to fetch feed', err))
-      .then(() => setHasSetup(author))
-  }, [route.params.name, feedView?.params.author, store])
-
-  useEffect(() => {
-    return navigation.addListener('focus', () => {
-      if (hasSetup === feedView?.params.author) {
-        console.log('Updating profile feed', hasSetup)
-        feedView?.update()
-      }
-    })
-  }, [navigation, feedView, hasSetup])
-
-  const onNavigateContent = (screen: string, props: Record<string, string>) => {
-    // @ts-ignore it's up to the callers to supply correct params -prf
-    navigation.push(screen, props)
-  }
-
-  return (
-    <Shell>
-      <View style={styles.container}>
-        <ProfileHeader
-          user={route.params.name}
-          onNavigateContent={onNavigateContent}
-        />
-        <View style={styles.feed}>
-          {feedView && (
-            <Feed feed={feedView} onNavigateContent={onNavigateContent} />
-          )}
-        </View>
-      </View>
-    </Shell>
-  )
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flexDirection: 'column',
-    height: '100%',
-  },
-  feed: {
-    flex: 1,
-  },
-})
diff --git a/src/view/screens/stacks/ProfileFollowers.tsx b/src/view/screens/stacks/ProfileFollowers.tsx
deleted file mode 100644
index 48fbb4e13..000000000
--- a/src/view/screens/stacks/ProfileFollowers.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import React, {useLayoutEffect} from 'react'
-import {TouchableOpacity} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {Shell} from '../../shell'
-import type {RootTabsScreenProps} from '../../routes/types'
-import {ProfileFollowers as ProfileFollowersComponent} from '../../com/profile/ProfileFollowers'
-
-export const ProfileFollowers = ({
-  navigation,
-  route,
-}: RootTabsScreenProps<'ProfileFollowers'>) => {
-  const {name} = route.params
-
-  useLayoutEffect(() => {
-    navigation.setOptions({
-      headerShown: true,
-      headerTitle: 'Followers',
-      headerLeft: () => (
-        <TouchableOpacity onPress={() => navigation.goBack()}>
-          <FontAwesomeIcon icon="arrow-left" />
-        </TouchableOpacity>
-      ),
-    })
-  }, [navigation])
-
-  const onNavigateContent = (screen: string, props: Record<string, string>) => {
-    // @ts-ignore it's up to the callers to supply correct params -prf
-    navigation.push(screen, props)
-  }
-
-  return (
-    <Shell>
-      <ProfileFollowersComponent
-        name={name}
-        onNavigateContent={onNavigateContent}
-      />
-    </Shell>
-  )
-}
diff --git a/src/view/screens/stacks/ProfileFollows.tsx b/src/view/screens/stacks/ProfileFollows.tsx
deleted file mode 100644
index 6fce3d798..000000000
--- a/src/view/screens/stacks/ProfileFollows.tsx
+++ /dev/null
@@ -1,39 +0,0 @@
-import React, {useLayoutEffect} from 'react'
-import {TouchableOpacity} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {Shell} from '../../shell'
-import type {RootTabsScreenProps} from '../../routes/types'
-import {ProfileFollows as ProfileFollowsComponent} from '../../com/profile/ProfileFollows'
-
-export const ProfileFollows = ({
-  navigation,
-  route,
-}: RootTabsScreenProps<'ProfileFollows'>) => {
-  const {name} = route.params
-
-  useLayoutEffect(() => {
-    navigation.setOptions({
-      headerShown: true,
-      headerTitle: 'Following',
-      headerLeft: () => (
-        <TouchableOpacity onPress={() => navigation.goBack()}>
-          <FontAwesomeIcon icon="arrow-left" />
-        </TouchableOpacity>
-      ),
-    })
-  }, [navigation])
-
-  const onNavigateContent = (screen: string, props: Record<string, string>) => {
-    // @ts-ignore it's up to the callers to supply correct params -prf
-    navigation.push(screen, props)
-  }
-
-  return (
-    <Shell>
-      <ProfileFollowsComponent
-        name={name}
-        onNavigateContent={onNavigateContent}
-      />
-    </Shell>
-  )
-}
diff --git a/src/view/screens/tabroots/Home.tsx b/src/view/screens/tabroots/Home.tsx
deleted file mode 100644
index a9c952473..000000000
--- a/src/view/screens/tabroots/Home.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, {useState, useEffect, useLayoutEffect} from 'react'
-import {Image, StyleSheet, TouchableOpacity, View} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {Shell} from '../../shell'
-import {Feed} from '../../com/feed/Feed'
-import type {RootTabsScreenProps} from '../../routes/types'
-import {useStores} from '../../../state'
-import {AVIS} from '../../lib/assets'
-
-export function Home({navigation}: RootTabsScreenProps<'HomeTab'>) {
-  const [hasSetup, setHasSetup] = useState<boolean>(false)
-  const store = useStores()
-  useEffect(() => {
-    console.log('Fetching home feed')
-    store.homeFeed.setup().then(() => setHasSetup(true))
-  }, [store.homeFeed])
-
-  const onNavigateContent = (screen: string, props: Record<string, string>) => {
-    // @ts-ignore it's up to the callers to supply correct params -prf
-    navigation.navigate(screen, props)
-  }
-
-  useEffect(() => {
-    return navigation.addListener('focus', () => {
-      if (hasSetup) {
-        console.log('Updating home feed')
-        store.homeFeed.update()
-      }
-    })
-  }, [navigation, store.homeFeed, hasSetup])
-
-  useLayoutEffect(() => {
-    navigation.setOptions({
-      headerShown: true,
-      headerTitle: 'V I B E',
-      headerLeft: () => (
-        <TouchableOpacity
-          onPress={() => navigation.push('Profile', {name: 'alice.com'})}>
-          <Image source={AVIS['alice.com']} style={styles.avi} />
-        </TouchableOpacity>
-      ),
-      headerRight: () => (
-        <TouchableOpacity
-          onPress={() => {
-            navigation.push('Composer', {})
-          }}>
-          <FontAwesomeIcon icon="plus" style={{color: '#006bf7'}} />
-        </TouchableOpacity>
-      ),
-    })
-  }, [navigation])
-
-  return (
-    <Shell>
-      <View>
-        <Feed feed={store.homeFeed} onNavigateContent={onNavigateContent} />
-      </View>
-    </Shell>
-  )
-}
-
-const styles = StyleSheet.create({
-  avi: {
-    width: 20,
-    height: 20,
-    borderRadius: 10,
-    resizeMode: 'cover',
-  },
-})
diff --git a/src/view/screens/tabroots/Menu.tsx b/src/view/screens/tabroots/Menu.tsx
deleted file mode 100644
index dca5ad33b..000000000
--- a/src/view/screens/tabroots/Menu.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react'
-import {Shell} from '../../shell'
-import {ScrollView, Text, View} from 'react-native'
-import type {RootTabsScreenProps} from '../../routes/types'
-
-export const Menu = (_props: RootTabsScreenProps<'MenuTab'>) => {
-  return (
-    <Shell>
-      <ScrollView contentInsetAdjustmentBehavior="automatic">
-        <View style={{justifyContent: 'center', alignItems: 'center'}}>
-          <Text style={{fontSize: 20, fontWeight: 'bold'}}>Menu</Text>
-        </View>
-      </ScrollView>
-    </Shell>
-  )
-}
diff --git a/src/view/screens/tabroots/NotFound.tsx b/src/view/screens/tabroots/NotFound.tsx
deleted file mode 100644
index a35808cbc..000000000
--- a/src/view/screens/tabroots/NotFound.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from 'react'
-import {Shell} from '../../shell'
-import {Text, Button, View} from 'react-native'
-import type {RootTabsScreenProps} from '../../routes/types'
-
-export const NotFound = ({navigation}: RootTabsScreenProps<'NotFound'>) => {
-  return (
-    <Shell>
-      <View style={{justifyContent: 'center', alignItems: 'center'}}>
-        <Text style={{fontSize: 20, fontWeight: 'bold'}}>Page not found</Text>
-        <Button title="Home" onPress={() => navigation.navigate('HomeTab')} />
-      </View>
-    </Shell>
-  )
-}
diff --git a/src/view/screens/tabroots/Notifications.tsx b/src/view/screens/tabroots/Notifications.tsx
deleted file mode 100644
index ea7576799..000000000
--- a/src/view/screens/tabroots/Notifications.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import React, {useState, useEffect, useLayoutEffect} from 'react'
-import {Image, StyleSheet, TouchableOpacity, View} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {Shell} from '../../shell'
-import {Feed} from '../../com/notifications/Feed'
-import type {RootTabsScreenProps} from '../../routes/types'
-import {useStores} from '../../../state'
-import {AVIS} from '../../lib/assets'
-
-export const Notifications = ({
-  navigation,
-}: RootTabsScreenProps<'NotificationsTab'>) => {
-  const [hasSetup, setHasSetup] = useState<boolean>(false)
-  const store = useStores()
-  useEffect(() => {
-    console.log('Fetching home feed')
-    store.notesFeed.setup().then(() => setHasSetup(true))
-  }, [store.notesFeed])
-
-  const onNavigateContent = (screen: string, props: Record<string, string>) => {
-    // @ts-ignore it's up to the callers to supply correct params -prf
-    navigation.navigate(screen, props)
-  }
-
-  useEffect(() => {
-    return navigation.addListener('focus', () => {
-      if (hasSetup) {
-        console.log('Updating home feed')
-        store.notesFeed.update()
-      }
-    })
-  }, [navigation, store.notesFeed, hasSetup])
-
-  useLayoutEffect(() => {
-    navigation.setOptions({
-      headerShown: true,
-      headerTitle: 'Notifications',
-      headerLeft: () => (
-        <TouchableOpacity
-          onPress={() => navigation.push('Profile', {name: 'alice.com'})}>
-          <Image source={AVIS['alice.com']} style={styles.avi} />
-        </TouchableOpacity>
-      ),
-      headerRight: () => (
-        <TouchableOpacity
-          onPress={() => {
-            navigation.push('Composer', {})
-          }}>
-          <FontAwesomeIcon icon="plus" style={{color: '#006bf7'}} />
-        </TouchableOpacity>
-      ),
-    })
-  }, [navigation])
-
-  return (
-    <Shell>
-      <View>
-        <Feed view={store.notesFeed} onNavigateContent={onNavigateContent} />
-      </View>
-    </Shell>
-  )
-}
-
-const styles = StyleSheet.create({
-  avi: {
-    width: 20,
-    height: 20,
-    borderRadius: 10,
-    resizeMode: 'cover',
-  },
-})
diff --git a/src/view/screens/tabroots/Search.tsx b/src/view/screens/tabroots/Search.tsx
deleted file mode 100644
index 044ca749c..000000000
--- a/src/view/screens/tabroots/Search.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react'
-import {Shell} from '../../shell'
-import {Text, View} from 'react-native'
-import type {RootTabsScreenProps} from '../../routes/types'
-
-export const Search = (_props: RootTabsScreenProps<'SearchTab'>) => {
-  return (
-    <Shell>
-      <View style={{justifyContent: 'center', alignItems: 'center'}}>
-        <Text style={{fontSize: 20, fontWeight: 'bold'}}>Search</Text>
-      </View>
-    </Shell>
-  )
-}