about summary refs log tree commit diff
path: root/src/view
diff options
context:
space:
mode:
Diffstat (limited to 'src/view')
-rw-r--r--src/view/com/feed/FeedItem.tsx33
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx33
-rw-r--r--src/view/index.ts2
-rw-r--r--src/view/lib/assets.native.ts7
-rw-r--r--src/view/lib/assets.ts7
-rw-r--r--src/view/routes/index.tsx79
-rw-r--r--src/view/routes/types.ts13
-rw-r--r--src/view/screens/Home.tsx5
-rw-r--r--src/view/screens/Menu.tsx2
-rw-r--r--src/view/screens/NotFound.tsx2
-rw-r--r--src/view/screens/Notifications.tsx4
-rw-r--r--src/view/screens/Search.tsx2
-rw-r--r--src/view/screens/content/PostThread.tsx19
13 files changed, 128 insertions, 80 deletions
diff --git a/src/view/com/feed/FeedItem.tsx b/src/view/com/feed/FeedItem.tsx
index 18af53dde..9cf70578c 100644
--- a/src/view/com/feed/FeedItem.tsx
+++ b/src/view/com/feed/FeedItem.tsx
@@ -1,25 +1,13 @@
 import React from 'react'
 import {observer} from 'mobx-react-lite'
-import {
-  Image,
-  ImageSourcePropType,
-  StyleSheet,
-  Text,
-  TouchableOpacity,
-  View,
-} from 'react-native'
+import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
 import {bsky, AdxUri} from '@adxp/mock-api'
 import moment from 'moment'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {OnNavigateContent} from '../../routes/types'
 import {FeedViewItemModel} from '../../../state/models/feed-view'
 import {s} from '../../lib/styles'
-
-const IMAGES: Record<string, ImageSourcePropType> = {
-  'alice.com': require('../../assets/alice.jpg'),
-  'bob.com': require('../../assets/bob.jpg'),
-  'carla.com': require('../../assets/carla.jpg'),
-}
+import {AVIS} from '../../lib/assets'
 
 export const FeedItem = observer(function FeedItem({
   item,
@@ -40,10 +28,7 @@ export const FeedItem = observer(function FeedItem({
     <TouchableOpacity style={styles.outer} onPress={onPressOuter}>
       {item.repostedBy && (
         <View style={styles.repostedBy}>
-          <FontAwesomeIcon
-            icon="retweet"
-            style={[styles.repostedByIcon, s.gray]}
-          />
+          <FontAwesomeIcon icon="retweet" style={styles.repostedByIcon} />
           <Text style={[s.gray, s.bold, s.f13]}>
             Reposted by {item.repostedBy.displayName}
           </Text>
@@ -53,7 +38,7 @@ export const FeedItem = observer(function FeedItem({
         <View style={styles.layoutAvi}>
           <Image
             style={styles.avi}
-            source={IMAGES[item.author.name] || IMAGES['alice.com']}
+            source={AVIS[item.author.name] || AVIS['alice.com']}
           />
         </View>
         <View style={styles.layoutContent}>
@@ -74,14 +59,14 @@ export const FeedItem = observer(function FeedItem({
           <View style={styles.ctrls}>
             <View style={styles.ctrl}>
               <FontAwesomeIcon
-                style={[styles.ctrlIcon, s.gray]}
+                style={styles.ctrlIcon}
                 icon={['far', 'comment']}
               />
               <Text>{item.replyCount}</Text>
             </View>
             <View style={styles.ctrl}>
               <FontAwesomeIcon
-                style={[styles.ctrlIcon, s.gray]}
+                style={styles.ctrlIcon}
                 icon="retweet"
                 size={22}
               />
@@ -89,14 +74,14 @@ export const FeedItem = observer(function FeedItem({
             </View>
             <View style={styles.ctrl}>
               <FontAwesomeIcon
-                style={[styles.ctrlIcon, s.gray]}
+                style={styles.ctrlIcon}
                 icon={['far', 'heart']}
               />
               <Text>{item.likeCount}</Text>
             </View>
             <View style={styles.ctrl}>
               <FontAwesomeIcon
-                style={[styles.ctrlIcon, s.gray]}
+                style={styles.ctrlIcon}
                 icon="share-from-square"
               />
             </View>
@@ -120,6 +105,7 @@ const styles = StyleSheet.create({
   },
   repostedByIcon: {
     marginRight: 2,
+    color: 'gray',
   },
   layout: {
     flexDirection: 'row',
@@ -159,5 +145,6 @@ const styles = StyleSheet.create({
   },
   ctrlIcon: {
     marginRight: 5,
+    color: 'gray',
   },
 })
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 2b72b7e4b..5e01ac0a6 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -1,13 +1,6 @@
 import React from 'react'
 import {observer} from 'mobx-react-lite'
-import {
-  Image,
-  ImageSourcePropType,
-  StyleSheet,
-  Text,
-  TouchableOpacity,
-  View,
-} from 'react-native'
+import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
 import {bsky, AdxUri} from '@adxp/mock-api'
 import moment from 'moment'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
@@ -15,14 +8,9 @@ import {OnNavigateContent} from '../../routes/types'
 import {PostThreadViewPostModel} from '../../../state/models/post-thread-view'
 import {s} from '../../lib/styles'
 import {pluralize} from '../../lib/strings'
+import {AVIS} from '../../lib/assets'
 
-const IMAGES: Record<string, ImageSourcePropType> = {
-  'alice.com': require('../../assets/alice.jpg'),
-  'bob.com': require('../../assets/bob.jpg'),
-  'carla.com': require('../../assets/carla.jpg'),
-}
-
-function iter<T>(n: number, fn: (i: number) => T): Array<T> {
+function iter<T>(n: number, fn: (_i: number) => T): Array<T> {
   const arr: T[] = []
   for (let i = 0; i < n; i++) {
     arr.push(fn(i))
@@ -49,13 +37,13 @@ export const PostThreadItem = observer(function PostThreadItem({
   return (
     <TouchableOpacity style={styles.outer} onPress={onPressOuter}>
       <View style={styles.layout}>
-        {iter(Math.abs(item._depth), () => (
-          <View style={styles.replyBar} />
+        {iter(Math.abs(item._depth), (i: number) => (
+          <View key={i} style={styles.replyBar} />
         ))}
         <View style={styles.layoutAvi}>
           <Image
             style={styles.avi}
-            source={IMAGES[item.author.name] || IMAGES['alice.com']}
+            source={AVIS[item.author.name] || AVIS['alice.com']}
           />
         </View>
         <View style={styles.layoutContent}>
@@ -104,14 +92,14 @@ export const PostThreadItem = observer(function PostThreadItem({
           <View style={styles.ctrls}>
             <View style={styles.ctrl}>
               <FontAwesomeIcon
-                style={[styles.ctrlIcon, s.gray]}
+                style={styles.ctrlIcon}
                 icon={['far', 'comment']}
               />
               <Text>{item.replyCount}</Text>
             </View>
             <View style={styles.ctrl}>
               <FontAwesomeIcon
-                style={[styles.ctrlIcon, s.gray]}
+                style={styles.ctrlIcon}
                 icon="retweet"
                 size={22}
               />
@@ -119,14 +107,14 @@ export const PostThreadItem = observer(function PostThreadItem({
             </View>
             <View style={styles.ctrl}>
               <FontAwesomeIcon
-                style={[styles.ctrlIcon, s.gray]}
+                style={styles.ctrlIcon}
                 icon={['far', 'heart']}
               />
               <Text>{item.likeCount}</Text>
             </View>
             <View style={styles.ctrl}>
               <FontAwesomeIcon
-                style={[styles.ctrlIcon, s.gray]}
+                style={styles.ctrlIcon}
                 icon="share-from-square"
               />
             </View>
@@ -204,5 +192,6 @@ const styles = StyleSheet.create({
   },
   ctrlIcon: {
     marginRight: 5,
+    color: 'gray',
   },
 })
diff --git a/src/view/index.ts b/src/view/index.ts
index d636844cc..8e3b00798 100644
--- a/src/view/index.ts
+++ b/src/view/index.ts
@@ -1,6 +1,7 @@
 import moment from 'moment'
 import {library} from '@fortawesome/fontawesome-svg-core'
 
+import {faArrowLeft} from '@fortawesome/free-solid-svg-icons/faArrowLeft'
 import {faBars} from '@fortawesome/free-solid-svg-icons/faBars'
 import {faBell} from '@fortawesome/free-solid-svg-icons/faBell'
 import {faComment} from '@fortawesome/free-regular-svg-icons/faComment'
@@ -32,6 +33,7 @@ export function setup() {
     },
   })
   library.add(
+    faArrowLeft,
     faBars,
     faBell,
     faComment,
diff --git a/src/view/lib/assets.native.ts b/src/view/lib/assets.native.ts
new file mode 100644
index 000000000..af5ee2bac
--- /dev/null
+++ b/src/view/lib/assets.native.ts
@@ -0,0 +1,7 @@
+import {ImageSourcePropType} from 'react-native'
+
+export const AVIS: Record<string, ImageSourcePropType> = {
+  'alice.com': require('../../../public/img/alice.jpg'),
+  'bob.com': require('../../../public/img/bob.jpg'),
+  'carla.com': require('../../../public/img/carla.jpg'),
+}
diff --git a/src/view/lib/assets.ts b/src/view/lib/assets.ts
new file mode 100644
index 000000000..7d0584a41
--- /dev/null
+++ b/src/view/lib/assets.ts
@@ -0,0 +1,7 @@
+import {ImageSourcePropType} from 'react-native'
+
+export const AVIS: Record<string, ImageSourcePropType> = {
+  'alice.com': {uri: '/img/alice.jpg'},
+  'bob.com': {uri: '/img/bob.jpg'},
+  'carla.com': {uri: '/img/carla.jpg'},
+}
diff --git a/src/view/routes/index.tsx b/src/view/routes/index.tsx
index 24d47a93c..58aa0ad8b 100644
--- a/src/view/routes/index.tsx
+++ b/src/view/routes/index.tsx
@@ -1,5 +1,5 @@
 import React, {useEffect} from 'react'
-import {Text, Linking} from 'react-native'
+import {Linking, Text} from 'react-native'
 import {
   NavigationContainer,
   LinkingOptions,
@@ -32,12 +32,12 @@ const linking: LinkingOptions<RootTabsParamList> = {
   ],
   config: {
     screens: {
-      Home: '',
+      HomeTab: '',
+      SearchTab: 'search',
+      NotificationsTab: 'notifications',
+      MenuTab: 'menu',
       Profile: 'profile/:name',
       PostThread: 'profile/:name/post/:recordKey',
-      Search: 'search',
-      Notifications: 'notifications',
-      Menu: 'menu',
       Login: 'login',
       Signup: 'signup',
       NotFound: '*',
@@ -46,7 +46,9 @@ const linking: LinkingOptions<RootTabsParamList> = {
 }
 
 export const RootTabs = createBottomTabNavigator<RootTabsParamList>()
-export const PrimaryStack = createNativeStackNavigator()
+export const HomeTabStack = createNativeStackNavigator()
+export const SearchTabStack = createNativeStackNavigator()
+export const NotificationsTabStack = createNativeStackNavigator()
 
 const tabBarScreenOptions = ({
   route,
@@ -56,18 +58,18 @@ const tabBarScreenOptions = ({
   headerShown: false,
   tabBarIcon: (state: {focused: boolean; color: string; size: number}) => {
     switch (route.name) {
-      case 'Home':
+      case 'HomeTab':
         return <FontAwesomeIcon icon="house" style={{color: state.color}} />
-      case 'Search':
+      case 'SearchTab':
         return (
           <FontAwesomeIcon
             icon="magnifying-glass"
             style={{color: state.color}}
           />
         )
-      case 'Notifications':
+      case 'NotificationsTab':
         return <FontAwesomeIcon icon="bell" style={{color: state.color}} />
-      case 'Menu':
+      case 'MenuTab':
         return <FontAwesomeIcon icon="bars" style={{color: state.color}} />
       default:
         return <FontAwesomeIcon icon="bars" style={{color: state.color}} />
@@ -75,8 +77,46 @@ const tabBarScreenOptions = ({
   },
 })
 
+const HIDE_HEADER = {headerShown: false}
 const HIDE_TAB = {tabBarButton: () => null}
 
+function HomeStackCom() {
+  return (
+    <HomeTabStack.Navigator>
+      <HomeTabStack.Screen name="Home" component={Home} options={HIDE_HEADER} />
+      <HomeTabStack.Screen name="Profile" component={Profile} />
+      <HomeTabStack.Screen name="PostThread" component={PostThread} />
+    </HomeTabStack.Navigator>
+  )
+}
+
+function SearchStackCom() {
+  return (
+    <SearchTabStack.Navigator>
+      <SearchTabStack.Screen
+        name="Search"
+        component={Search}
+        options={HIDE_HEADER}
+      />
+      <SearchTabStack.Screen name="Profile" component={Profile} />
+      <SearchTabStack.Screen name="PostThread" component={PostThread} />
+    </SearchTabStack.Navigator>
+  )
+}
+
+function NotificationsStackCom() {
+  return (
+    <NotificationsTabStack.Navigator>
+      <NotificationsTabStack.Screen
+        name="Notifications"
+        component={Notifications}
+      />
+      <NotificationsTabStack.Screen name="Profile" component={Profile} />
+      <NotificationsTabStack.Screen name="PostThread" component={PostThread} />
+    </NotificationsTabStack.Navigator>
+  )
+}
+
 export const Root = observer(() => {
   const store = useStores()
 
@@ -96,25 +136,18 @@ export const Root = observer(() => {
   return (
     <NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
       <RootTabs.Navigator
-        initialRouteName={store.session.isAuthed ? 'Home' : 'Login'}
+        initialRouteName={store.session.isAuthed ? 'HomeTab' : 'Login'}
         screenOptions={tabBarScreenOptions}
         tabBar={tabBar}>
         {store.session.isAuthed ? (
           <>
-            <RootTabs.Screen name="Home" component={Home} />
-            <RootTabs.Screen name="Search" component={Search} />
-            <RootTabs.Screen name="Notifications" component={Notifications} />
-            <RootTabs.Screen name="Menu" component={Menu} />
-            <RootTabs.Screen
-              name="Profile"
-              component={Profile}
-              options={HIDE_TAB}
-            />
+            <RootTabs.Screen name="HomeTab" component={HomeStackCom} />
+            <RootTabs.Screen name="SearchTab" component={SearchStackCom} />
             <RootTabs.Screen
-              name="PostThread"
-              component={PostThread}
-              options={HIDE_TAB}
+              name="NotificationsTab"
+              component={NotificationsStackCom}
             />
+            <RootTabs.Screen name="MenuTab" component={Menu} />
           </>
         ) : (
           <>
diff --git a/src/view/routes/types.ts b/src/view/routes/types.ts
index bca6f196a..0b4bbc5d7 100644
--- a/src/view/routes/types.ts
+++ b/src/view/routes/types.ts
@@ -1,10 +1,10 @@
 import type {StackScreenProps} from '@react-navigation/stack'
 
 export type RootTabsParamList = {
-  Home: undefined
-  Search: undefined
-  Notifications: undefined
-  Menu: undefined
+  HomeTab: undefined
+  SearchTab: undefined
+  NotificationsTab: undefined
+  MenuTab: undefined
   Profile: {name: string}
   PostThread: {name: string; recordKey: string}
   Login: undefined
@@ -14,7 +14,10 @@ export type RootTabsParamList = {
 export type RootTabsScreenProps<T extends keyof RootTabsParamList> =
   StackScreenProps<RootTabsParamList, T>
 
-export type OnNavigateContent = (screen: string, params: Record<string, string>): void
+export type OnNavigateContent = (
+  screen: string,
+  params: Record<string, string>,
+) => void
 
 /*
 NOTE
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 4a3e41a75..1b41b2d35 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -5,15 +5,18 @@ import {Feed} from '../com/feed/Feed'
 import type {RootTabsScreenProps} from '../routes/types'
 import {useStores} from '../../state'
 
-export function Home({navigation}: RootTabsScreenProps<'Home'>) {
+export function Home({navigation}: RootTabsScreenProps<'HomeTab'>) {
   const store = useStores()
   useEffect(() => {
     console.log('Fetching home feed')
     store.homeFeed.setup()
   }, [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)
   }
+
   return (
     <Shell>
       <View>
diff --git a/src/view/screens/Menu.tsx b/src/view/screens/Menu.tsx
index 8cf93676e..d0cc0826f 100644
--- a/src/view/screens/Menu.tsx
+++ b/src/view/screens/Menu.tsx
@@ -3,7 +3,7 @@ import {Shell} from '../shell'
 import {ScrollView, Text, View} from 'react-native'
 import type {RootTabsScreenProps} from '../routes/types'
 
-export const Menu = (_props: RootTabsScreenProps<'Menu'>) => {
+export const Menu = (_props: RootTabsScreenProps<'MenuTab'>) => {
   return (
     <Shell>
       <ScrollView contentInsetAdjustmentBehavior="automatic">
diff --git a/src/view/screens/NotFound.tsx b/src/view/screens/NotFound.tsx
index 3f6dd7aa0..5357a428a 100644
--- a/src/view/screens/NotFound.tsx
+++ b/src/view/screens/NotFound.tsx
@@ -8,7 +8,7 @@ export const NotFound = ({navigation}: RootTabsScreenProps<'NotFound'>) => {
     <Shell>
       <View style={{justifyContent: 'center', alignItems: 'center'}}>
         <Text style={{fontSize: 20, fontWeight: 'bold'}}>Page not found</Text>
-        <Button title="Home" onPress={() => navigation.navigate('Home')} />
+        <Button title="Home" onPress={() => navigation.navigate('HomeTab')} />
       </View>
     </Shell>
   )
diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx
index 5bade68fa..a7918f177 100644
--- a/src/view/screens/Notifications.tsx
+++ b/src/view/screens/Notifications.tsx
@@ -3,7 +3,9 @@ import {Shell} from '../shell'
 import {Text, View} from 'react-native'
 import type {RootTabsScreenProps} from '../routes/types'
 
-export const Notifications = (_props: RootTabsScreenProps<'Notifications'>) => {
+export const Notifications = (
+  _props: RootTabsScreenProps<'NotificationsTab'>,
+) => {
   return (
     <Shell>
       <View style={{justifyContent: 'center', alignItems: 'center'}}>
diff --git a/src/view/screens/Search.tsx b/src/view/screens/Search.tsx
index 2f111cf72..26df2954c 100644
--- a/src/view/screens/Search.tsx
+++ b/src/view/screens/Search.tsx
@@ -3,7 +3,7 @@ import {Shell} from '../shell'
 import {Text, View} from 'react-native'
 import type {RootTabsScreenProps} from '../routes/types'
 
-export const Search = (_props: RootTabsScreenProps<'Search'>) => {
+export const Search = (_props: RootTabsScreenProps<'SearchTab'>) => {
   return (
     <Shell>
       <View style={{justifyContent: 'center', alignItems: 'center'}}>
diff --git a/src/view/screens/content/PostThread.tsx b/src/view/screens/content/PostThread.tsx
index 5b8fa951c..e990bcc1b 100644
--- a/src/view/screens/content/PostThread.tsx
+++ b/src/view/screens/content/PostThread.tsx
@@ -1,4 +1,6 @@
-import React from 'react'
+import React, {useLayoutEffect} from 'react'
+import {TouchableOpacity} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {AdxUri} from '@adxp/mock-api'
 import {Shell} from '../../shell'
 import type {RootTabsScreenProps} from '../../routes/types'
@@ -16,8 +18,21 @@ export const PostThread = ({
   urip.recordKey = recordKey
   const uri = urip.toString()
 
+  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>) => {
-    navigation.navigate(screen, props)
+    // @ts-ignore it's up to the callers to supply correct params -prf
+    navigation.push(screen, props)
   }
   return (
     <Shell>