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/modals/EditProfile.tsx8
-rw-r--r--src/view/com/modals/Modal.tsx2
-rw-r--r--src/view/com/notifications/Feed.tsx4
-rw-r--r--src/view/com/notifications/FeedItem.tsx51
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx9
-rw-r--r--src/view/com/post/Post.tsx27
-rw-r--r--src/view/lib/styles.ts2
-rw-r--r--src/view/screens/Notifications.tsx32
-rw-r--r--src/view/shell/mobile/index.tsx4
9 files changed, 88 insertions, 51 deletions
diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx
index 50acccf67..1b5c99d97 100644
--- a/src/view/com/modals/EditProfile.tsx
+++ b/src/view/com/modals/EditProfile.tsx
@@ -65,8 +65,8 @@ export function Component({
 
   return (
     <View style={s.flex1}>
-      <Text style={[s.textCenter, s.bold, s.f16]}>Edit my profile</Text>
       <BottomSheetScrollView style={styles.inner}>
+        <Text style={styles.title}>Edit my profile</Text>
         {error !== '' && (
           <View style={s.mb10}>
             <ErrorMessage message={error} />
@@ -114,6 +114,12 @@ const styles = StyleSheet.create({
   inner: {
     padding: 14,
   },
+  title: {
+    textAlign: 'center',
+    fontWeight: 'bold',
+    fontSize: 24,
+    marginBottom: 18,
+  },
   group: {
     marginBottom: 10,
   },
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index 9d7033411..47b627435 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -35,7 +35,7 @@ export const Modal = observer(function Modal() {
     } else {
       bottomSheetRef.current?.close()
     }
-  }, [store.shell.isModalActive, bottomSheetRef])
+  }, [store.shell.isModalActive, bottomSheetRef, store.shell.activeModal?.name])
 
   let snapPoints: (string | number)[] = CLOSED_SNAPPOINTS
   let element
diff --git a/src/view/com/notifications/Feed.tsx b/src/view/com/notifications/Feed.tsx
index 90d16604d..d3a911f2a 100644
--- a/src/view/com/notifications/Feed.tsx
+++ b/src/view/com/notifications/Feed.tsx
@@ -43,7 +43,7 @@ export const Feed = observer(function Feed({
           onPressTryAgain={onPressTryAgain}
         />
       )}
-      {view.hasContent && (
+      {view.hasLoaded && (
         <FlatList
           data={view.notifications}
           keyExtractor={item => item._reactKey}
@@ -53,7 +53,7 @@ export const Feed = observer(function Feed({
           onEndReached={onEndReached}
         />
       )}
-      {view.isEmpty && (
+      {view.hasLoaded && view.isEmpty && (
         <EmptyState icon="bell" message="No notifications yet!" />
       )}
     </View>
diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx
index 8741e4236..166b1bf99 100644
--- a/src/view/com/notifications/FeedItem.tsx
+++ b/src/view/com/notifications/FeedItem.tsx
@@ -4,11 +4,12 @@ import {StyleSheet, Text, View} from 'react-native'
 import {AtUri} from '../../../third-party/uri'
 import {FontAwesomeIcon, Props} from '@fortawesome/react-native-fontawesome'
 import {NotificationsViewItemModel} from '../../../state/models/notifications-view'
+import {PostThreadViewModel} from '../../../state/models/post-thread-view'
 import {s, colors} from '../../lib/styles'
 import {ago, pluralize} from '../../../lib/strings'
 import {UpIconSolid} from '../../lib/icons'
 import {UserAvatar} from '../util/UserAvatar'
-import {PostText} from '../post/PostText'
+import {ErrorMessage} from '../util/ErrorMessage'
 import {Post} from '../post/Post'
 import {Link} from '../util/Link'
 import {InviteAccepter} from './InviteAccepter'
@@ -42,16 +43,22 @@ export const FeedItem = observer(function FeedItem({
     }
   }, [item])
 
+  if (item.additionalPost?.notFound) {
+    // don't render anything if the target post was deleted or unfindable
+    return <View />
+  }
+
   if (item.isReply) {
     return (
-      <Link
-        style={[
-          styles.outerMinimal,
-          item.isRead ? undefined : styles.outerUnread,
-        ]}
-        href={itemHref}
-        title={itemTitle}>
-        <Post uri={item.uri} />
+      <Link href={itemHref} title={itemTitle}>
+        <Post
+          uri={item.uri}
+          initView={item.additionalPost}
+          style={[
+            styles.outerMinimal,
+            item.isRead ? undefined : styles.outerUnread,
+          ]}
+        />
       </Link>
     )
   }
@@ -170,7 +177,7 @@ export const FeedItem = observer(function FeedItem({
             </Text>
           </View>
           {item.isUpvote || item.isRepost || item.isTrend ? (
-            <PostText uri={item.subjectUri} style={[s.gray5]} />
+            <AdditionalPostText additionalPost={item.additionalPost} />
           ) : (
             <></>
           )}
@@ -181,17 +188,24 @@ export const FeedItem = observer(function FeedItem({
           <InviteAccepter item={item} />
         </View>
       )}
-      {item.isReply ? (
-        <View style={s.pt5}>
-          <Post uri={item.uri} />
-        </View>
-      ) : (
-        <></>
-      )}
     </Link>
   )
 })
 
+function AdditionalPostText({
+  additionalPost,
+}: {
+  additionalPost?: PostThreadViewModel
+}) {
+  if (!additionalPost) {
+    return <View />
+  }
+  if (additionalPost.error) {
+    return <ErrorMessage message={additionalPost.error} />
+  }
+  return <Text style={[s.gray5]}>{additionalPost.thread?.record.text}</Text>
+}
+
 const styles = StyleSheet.create({
   outer: {
     backgroundColor: colors.white,
@@ -207,8 +221,9 @@ const styles = StyleSheet.create({
     marginBottom: 0,
   },
   outerUnread: {
+    backgroundColor: colors.unreadNotifBg,
     borderWidth: 1,
-    borderColor: colors.blue2,
+    borderColor: colors.blue1,
   },
   layout: {
     flexDirection: 'row',
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 85c241ce4..d08ca3e4a 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -88,6 +88,15 @@ export const PostThreadItem = observer(function PostThreadItem({
     )
   }
 
+  if (deleted) {
+    return (
+      <View style={[styles.outer, s.p20, s.flexRow]}>
+        <FontAwesomeIcon icon={['far', 'trash-can']} style={[s.gray4]} />
+        <Text style={[s.gray5, s.ml10]}>This post has been deleted.</Text>
+      </View>
+    )
+  }
+
   if (item._isHighlightedPost) {
     return (
       <>
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index 4d668cac3..736b40157 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -1,8 +1,15 @@
 import React, {useState, useEffect} from 'react'
+import {
+  ActivityIndicator,
+  StyleProp,
+  StyleSheet,
+  Text,
+  View,
+  ViewStyle,
+} from 'react-native'
 import {observer} from 'mobx-react-lite'
 import {AtUri} from '../../../third-party/uri'
 import * as PostType from '../../../third-party/api/src/client/types/app/bsky/feed/post'
-import {ActivityIndicator, StyleSheet, Text, View} from 'react-native'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {PostThreadViewModel} from '../../../state/models/post-thread-view'
 import {Link} from '../util/Link'
@@ -15,19 +22,27 @@ import {UserAvatar} from '../util/UserAvatar'
 import {useStores} from '../../../state'
 import {s, colors} from '../../lib/styles'
 
-export const Post = observer(function Post({uri}: {uri: string}) {
+export const Post = observer(function Post({
+  uri,
+  initView,
+  style,
+}: {
+  uri: string
+  initView?: PostThreadViewModel
+  style?: StyleProp<ViewStyle>
+}) {
   const store = useStores()
-  const [view, setView] = useState<PostThreadViewModel | undefined>()
+  const [view, setView] = useState<PostThreadViewModel | undefined>(initView)
   const [deleted, setDeleted] = useState(false)
 
   useEffect(() => {
-    if (view?.params.uri === uri) {
+    if (initView || view?.params.uri === uri) {
       return // no change needed? or trigger refresh?
     }
     const newView = new PostThreadViewModel(store, {uri, depth: 0})
     setView(newView)
     newView.setup().catch(err => console.error('Failed to fetch post', err))
-  }, [uri, view?.params.uri, store])
+  }, [initView, uri, view?.params.uri, store])
 
   // deleted
   // =
@@ -109,7 +124,7 @@ export const Post = observer(function Post({uri}: {uri: string}) {
   }
 
   return (
-    <Link style={styles.outer} href={itemHref} title={itemTitle}>
+    <Link style={[styles.outer, style]} href={itemHref} title={itemTitle}>
       <View style={styles.layout}>
         <View style={styles.layoutAvi}>
           <Link href={authorHref} title={authorTitle}>
diff --git a/src/view/lib/styles.ts b/src/view/lib/styles.ts
index 8bb26ef88..1ac6283a2 100644
--- a/src/view/lib/styles.ts
+++ b/src/view/lib/styles.ts
@@ -41,6 +41,8 @@ export const colors = {
   green3: '#20bc07',
   green4: '#148203',
   green5: '#082b03',
+
+  unreadNotifBg: '#ebf6ff',
 }
 
 export const gradients = {
diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx
index 1e7abdb90..b168ffaff 100644
--- a/src/view/screens/Notifications.tsx
+++ b/src/view/screens/Notifications.tsx
@@ -7,43 +7,33 @@ import {NotificationsViewModel} from '../../state/models/notifications-view'
 import {ScreenParams} from '../routes'
 
 export const Notifications = ({navIdx, visible}: ScreenParams) => {
-  const [hasSetup, setHasSetup] = useState<boolean>(false)
-  const [notesView, setNotesView] = useState<
-    NotificationsViewModel | undefined
-  >()
   const store = useStores()
 
   useEffect(() => {
-    let aborted = false
     if (!visible) {
       return
     }
+    console.log('Updating notifications feed')
     store.me.refreshMemberships() // needed for the invite notifications
-    if (hasSetup) {
-      console.log('Updating notifications feed')
-      notesView?.update()
-    } else {
-      store.nav.setTitle(navIdx, 'Notifications')
-      const newNotesView = new NotificationsViewModel(store, {})
-      setNotesView(newNotesView)
-      newNotesView.setup().then(() => {
-        if (aborted) return
-        setHasSetup(true)
+    store.me.notifications
+      .update()
+      .catch(e => {
+        console.error('Error while updating notifications feed', e)
       })
-    }
-    return () => {
-      aborted = true
-    }
+      .then(() => {
+        store.me.notifications.updateReadState()
+      })
+    store.nav.setTitle(navIdx, 'Notifications')
   }, [visible, store])
 
   const onPressTryAgain = () => {
-    notesView?.refresh()
+    store.me.notifications.refresh()
   }
 
   return (
     <View style={{flex: 1}}>
       <ViewHeader title="Notifications" />
-      {notesView && <Feed view={notesView} onPressTryAgain={onPressTryAgain} />}
+      <Feed view={store.me.notifications} onPressTryAgain={onPressTryAgain} />
     </View>
   )
 }
diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx
index ccde52a2c..27524bcae 100644
--- a/src/view/shell/mobile/index.tsx
+++ b/src/view/shell/mobile/index.tsx
@@ -321,7 +321,7 @@ export const MobileShell: React.FC = observer(() => {
         <Btn
           icon={isAtHome ? 'home-solid' : 'home'}
           onPress={onPressHome}
-          onLongPress={doNewTab('/')}
+          onLongPress={TABS_ENABLED ? doNewTab('/') : undefined}
         />
         {TABS_ENABLED ? (
           <Btn
@@ -333,7 +333,7 @@ export const MobileShell: React.FC = observer(() => {
         <Btn
           icon={isAtNotifications ? 'bell-solid' : 'bell'}
           onPress={onPressNotifications}
-          onLongPress={doNewTab('/notifications')}
+          onLongPress={TABS_ENABLED ? doNewTab('/notifications') : undefined}
           notificationCount={store.me.notificationCount}
         />
         <Btn