about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2022-11-21 18:55:08 -0600
committerPaul Frazee <pfrazee@gmail.com>2022-11-21 18:55:08 -0600
commite858bb52de180645bba4f5ffa2f8bc0cfe8ad1fe (patch)
tree120b5be2ed657b7f8d30d56016d1a0857bb98086
parentb2dba9a15b0b27c9221808ff037090c2b4c2d500 (diff)
parent7e487fd5ae053ebb4373b85f1b3d7aa66f8a0241 (diff)
downloadvoidsky-e858bb52de180645bba4f5ffa2f8bc0cfe8ad1fe.tar.zst
Merge branch 'simplify' into main
-rw-r--r--src/build-flags.ts2
-rw-r--r--src/state/index.ts1
-rw-r--r--src/state/models/navigation.ts11
-rw-r--r--src/view/com/composer/Prompt.tsx63
-rw-r--r--src/view/com/modals/ServerInput.tsx4
-rw-r--r--src/view/com/onboard/FeatureExplainer.tsx5
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx34
-rw-r--r--src/view/com/post/Post.tsx8
-rw-r--r--src/view/com/posts/Feed.tsx15
-rw-r--r--src/view/com/posts/FeedItem.tsx8
-rw-r--r--src/view/com/profile/ProfileHeader.tsx38
-rw-r--r--src/view/com/util/DropdownBtn.tsx17
-rw-r--r--src/view/com/util/LoadingPlaceholder.tsx12
-rw-r--r--src/view/com/util/PostCtrls.tsx63
-rw-r--r--src/view/com/util/ViewHeader.tsx43
-rw-r--r--src/view/lib/icons.tsx41
-rw-r--r--src/view/screens/Home.tsx5
-rw-r--r--src/view/screens/Notifications.tsx5
-rw-r--r--src/view/screens/Profile.tsx5
-rw-r--r--src/view/shell/mobile/index.tsx32
20 files changed, 180 insertions, 232 deletions
diff --git a/src/build-flags.ts b/src/build-flags.ts
new file mode 100644
index 000000000..155230e5d
--- /dev/null
+++ b/src/build-flags.ts
@@ -0,0 +1,2 @@
+export const LOGIN_INCLUDE_DEV_SERVERS = true
+export const TABS_ENABLED = false
diff --git a/src/state/index.ts b/src/state/index.ts
index 7bb757757..32efea3f3 100644
--- a/src/state/index.ts
+++ b/src/state/index.ts
@@ -5,7 +5,6 @@ import {RootStoreModel} from './models/root-store'
 import * as libapi from './lib/api'
 import * as storage from './lib/storage'
 
-export const IS_PROD_BUILD = true
 export const LOCAL_DEV_SERVICE = 'http://localhost:2583'
 export const STAGING_SERVICE = 'https://pds.staging.bsky.dev'
 export const PROD_SERVICE = 'https://bsky.social'
diff --git a/src/state/models/navigation.ts b/src/state/models/navigation.ts
index a4d7d443b..1e639b0f3 100644
--- a/src/state/models/navigation.ts
+++ b/src/state/models/navigation.ts
@@ -1,5 +1,5 @@
 import {makeAutoObservable} from 'mobx'
-import {isObj, hasProp} from '../lib/type-guards'
+import {TABS_ENABLED} from '../../build-flags'
 
 let __id = 0
 function genId() {
@@ -244,6 +244,9 @@ export class NavigationModel {
   // =
 
   newTab(url: string, title?: string) {
+    if (!TABS_ENABLED) {
+      return this.navigate(url)
+    }
     const tab = new NavigationTabModel()
     tab.navigate(url, title)
     tab.isNewTab = true
@@ -252,10 +255,16 @@ export class NavigationModel {
   }
 
   setActiveTab(tabIndex: number) {
+    if (!TABS_ENABLED) {
+      return
+    }
     this.tabIndex = Math.max(Math.min(tabIndex, this.tabs.length - 1), 0)
   }
 
   closeTab(tabIndex: number) {
+    if (!TABS_ENABLED) {
+      return
+    }
     this.tabs = [
       ...this.tabs.slice(0, tabIndex),
       ...this.tabs.slice(tabIndex + 1),
diff --git a/src/view/com/composer/Prompt.tsx b/src/view/com/composer/Prompt.tsx
new file mode 100644
index 000000000..4a84c7160
--- /dev/null
+++ b/src/view/com/composer/Prompt.tsx
@@ -0,0 +1,63 @@
+import React from 'react'
+import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {colors} from '../../lib/styles'
+import {useStores} from '../../../state'
+import {UserAvatar} from '../util/UserAvatar'
+
+export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
+  const store = useStores()
+  const onPressAvatar = () => {
+    store.nav.navigate(`/profile/${store.me.handle}`)
+  }
+  return (
+    <TouchableOpacity style={styles.container} onPress={onPressCompose}>
+      <TouchableOpacity style={styles.avatar} onPress={onPressAvatar}>
+        <UserAvatar
+          size={50}
+          handle={store.me.handle || ''}
+          displayName={store.me.displayName}
+        />
+      </TouchableOpacity>
+      <View style={styles.textContainer}>
+        <Text style={styles.text}>What's happening?</Text>
+      </View>
+      <View style={styles.btn}>
+        <Text style={styles.btnText}>Post</Text>
+      </View>
+    </TouchableOpacity>
+  )
+}
+
+const styles = StyleSheet.create({
+  container: {
+    borderRadius: 6,
+    margin: 2,
+    marginBottom: 0,
+    paddingHorizontal: 10,
+    paddingVertical: 10,
+    flexDirection: 'row',
+    alignItems: 'center',
+    backgroundColor: colors.white,
+  },
+  avatar: {
+    width: 50,
+  },
+  textContainer: {
+    marginLeft: 10,
+    flex: 1,
+  },
+  text: {
+    color: colors.gray4,
+    fontSize: 17,
+  },
+  btn: {
+    backgroundColor: colors.gray1,
+    paddingVertical: 6,
+    paddingHorizontal: 14,
+    borderRadius: 30,
+  },
+  btnText: {
+    color: colors.gray5,
+  },
+})
diff --git a/src/view/com/modals/ServerInput.tsx b/src/view/com/modals/ServerInput.tsx
index 0aa1a07e2..c885ff164 100644
--- a/src/view/com/modals/ServerInput.tsx
+++ b/src/view/com/modals/ServerInput.tsx
@@ -5,11 +5,11 @@ import {BottomSheetScrollView, BottomSheetTextInput} from '@gorhom/bottom-sheet'
 import {useStores} from '../../../state'
 import {s, colors} from '../../lib/styles'
 import {
-  IS_PROD_BUILD,
   LOCAL_DEV_SERVICE,
   STAGING_SERVICE,
   PROD_SERVICE,
 } from '../../../state/index'
+import {LOGIN_INCLUDE_DEV_SERVERS} from '../../../build-flags'
 
 export const snapPoints = ['80%']
 
@@ -36,7 +36,7 @@ export function Component({
       <Text style={[s.textCenter, s.bold, s.f18]}>Choose Service</Text>
       <BottomSheetScrollView style={styles.inner}>
         <View style={styles.group}>
-          {!IS_PROD_BUILD ? (
+          {LOGIN_INCLUDE_DEV_SERVERS ? (
             <>
               <TouchableOpacity
                 style={styles.btn}
diff --git a/src/view/com/onboard/FeatureExplainer.tsx b/src/view/com/onboard/FeatureExplainer.tsx
index 0f8c52ea5..d9f70cf4f 100644
--- a/src/view/com/onboard/FeatureExplainer.tsx
+++ b/src/view/com/onboard/FeatureExplainer.tsx
@@ -15,6 +15,7 @@ import {UserGroupIcon} from '../../lib/icons'
 import {useStores} from '../../../state'
 import {s} from '../../lib/styles'
 import {SCENE_EXPLAINER, TABS_EXPLAINER} from '../../lib/assets'
+import {TABS_ENABLED} from '../../../build-flags'
 
 const Intro = () => (
   <View style={styles.explainer}>
@@ -85,8 +86,8 @@ export const FeatureExplainer = () => {
   const routes = [
     {key: 'intro', title: 'Intro'},
     {key: 'scenes', title: 'Scenes'},
-    {key: 'tabs', title: 'Tabs'},
-  ]
+    TABS_ENABLED ? {key: 'tabs', title: 'Tabs'} : undefined,
+  ].filter(Boolean)
 
   const onPressSkip = () => store.onboard.next()
   const onPressNext = () => {
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 665c87b46..83aac1010 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -29,8 +29,7 @@ export const PostThreadItem = observer(function PostThreadItem({
   const store = useStores()
   const [deleted, setDeleted] = useState(false)
   const record = item.record as unknown as PostType.Record
-  const hasEngagement =
-    item.upvoteCount || item.downvoteCount || item.repostCount
+  const hasEngagement = item.upvoteCount || item.repostCount
 
   const itemHref = useMemo(() => {
     const urip = new AtUri(item.uri)
@@ -44,11 +43,6 @@ export const PostThreadItem = observer(function PostThreadItem({
     return `/profile/${item.author.handle}/post/${urip.rkey}/upvoted-by`
   }, [item.uri, item.author.handle])
   const upvotesTitle = 'Upvotes on this post'
-  const downvotesHref = useMemo(() => {
-    const urip = new AtUri(item.uri)
-    return `/profile/${item.author.handle}/post/${urip.rkey}/downvoted-by`
-  }, [item.uri, item.author.handle])
-  const downvotesTitle = 'Downvotes on this post'
   const repostsHref = useMemo(() => {
     const urip = new AtUri(item.uri)
     return `/profile/${item.author.handle}/post/${urip.rkey}/reposted-by`
@@ -71,11 +65,6 @@ export const PostThreadItem = observer(function PostThreadItem({
       .toggleUpvote()
       .catch(e => console.error('Failed to toggle upvote', record, e))
   }
-  const onPressToggleDownvote = () => {
-    item
-      .toggleDownvote()
-      .catch(e => console.error('Failed to toggle downvote', record, e))
-  }
   const onDeletePost = () => {
     item.delete().then(
       () => {
@@ -186,21 +175,6 @@ export const PostThreadItem = observer(function PostThreadItem({
               ) : (
                 <></>
               )}
-              {item.downvoteCount ? (
-                <Link
-                  style={styles.expandedInfoItem}
-                  href={downvotesHref}
-                  title={downvotesTitle}>
-                  <Text style={[s.gray5, s.semiBold, s.f18]}>
-                    <Text style={[s.bold, s.black, s.f18]}>
-                      {item.downvoteCount}
-                    </Text>{' '}
-                    {pluralize(item.downvoteCount, 'downvote')}
-                  </Text>
-                </Link>
-              ) : (
-                <></>
-              )}
             </View>
           ) : (
             <></>
@@ -210,14 +184,11 @@ export const PostThreadItem = observer(function PostThreadItem({
               replyCount={item.replyCount}
               repostCount={item.repostCount}
               upvoteCount={item.upvoteCount}
-              downvoteCount={item.downvoteCount}
               isReposted={!!item.myState.repost}
               isUpvoted={!!item.myState.upvote}
-              isDownvoted={!!item.myState.downvote}
               onPressReply={onPressReply}
               onPressToggleRepost={onPressToggleRepost}
               onPressToggleUpvote={onPressToggleUpvote}
-              onPressToggleDownvote={onPressToggleDownvote}
             />
           </View>
         </View>
@@ -299,14 +270,11 @@ export const PostThreadItem = observer(function PostThreadItem({
               replyCount={item.replyCount}
               repostCount={item.repostCount}
               upvoteCount={item.upvoteCount}
-              downvoteCount={item.downvoteCount}
               isReposted={!!item.myState.repost}
               isUpvoted={!!item.myState.upvote}
-              isDownvoted={!!item.myState.downvote}
               onPressReply={onPressReply}
               onPressToggleRepost={onPressToggleRepost}
               onPressToggleUpvote={onPressToggleUpvote}
-              onPressToggleDownvote={onPressToggleDownvote}
             />
           </View>
         </View>
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index a5c084570..10f8048f0 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -85,11 +85,6 @@ export const Post = observer(function Post({uri}: {uri: string}) {
       .toggleUpvote()
       .catch(e => console.error('Failed to toggle upvote', record, e))
   }
-  const onPressToggleDownvote = () => {
-    item
-      .toggleDownvote()
-      .catch(e => console.error('Failed to toggle downvote', record, e))
-  }
   const onDeletePost = () => {
     item.delete().then(
       () => {
@@ -154,14 +149,11 @@ export const Post = observer(function Post({uri}: {uri: string}) {
             replyCount={item.replyCount}
             repostCount={item.repostCount}
             upvoteCount={item.upvoteCount}
-            downvoteCount={item.downvoteCount}
             isReposted={!!item.myState.repost}
             isUpvoted={!!item.myState.upvote}
-            isDownvoted={!!item.myState.downvote}
             onPressReply={onPressReply}
             onPressToggleRepost={onPressToggleRepost}
             onPressToggleUpvote={onPressToggleUpvote}
-            onPressToggleDownvote={onPressToggleDownvote}
           />
         </View>
       </View>
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index d10be821f..3a2bc6189 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -6,23 +6,34 @@ import {EmptyState} from '../util/EmptyState'
 import {ErrorMessage} from '../util/ErrorMessage'
 import {FeedModel, FeedItemModel} from '../../../state/models/feed-view'
 import {FeedItem} from './FeedItem'
+import {ComposePrompt} from '../composer/Prompt'
+
+const COMPOSE_PROMPT_ITEM = {_reactKey: '__prompt__'}
 
 export const Feed = observer(function Feed({
   feed,
   style,
   scrollElRef,
+  onPressCompose,
   onPressTryAgain,
 }: {
   feed: FeedModel
   style?: StyleProp<ViewStyle>
   scrollElRef?: MutableRefObject<FlatList<any> | null>
+  onPressCompose?: () => void
   onPressTryAgain?: () => void
 }) {
   // TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf
   //   VirtualizedList: You have a large list that is slow to update - make sure your
   //   renderItem function renders components that follow React performance best practices
   //   like PureComponent, shouldComponentUpdate, etc
-  const renderItem = ({item}: {item: FeedItemModel}) => <FeedItem item={item} />
+  const renderItem = ({item}: {item: FeedItemModel}) => {
+    if (item === COMPOSE_PROMPT_ITEM) {
+      return <ComposePrompt onPressCompose={onPressCompose} />
+    } else {
+      return <FeedItem item={item} />
+    }
+  }
   const onRefresh = () => {
     feed.refresh().catch(err => console.error('Failed to refresh', err))
   }
@@ -45,7 +56,7 @@ export const Feed = observer(function Feed({
       {feed.hasContent && (
         <FlatList
           ref={scrollElRef}
-          data={feed.feed.slice()}
+          data={[COMPOSE_PROMPT_ITEM].concat(feed.feed.slice())}
           keyExtractor={item => item._reactKey}
           renderItem={renderItem}
           refreshing={feed.isRefreshing}
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index 2898deff5..6deb04209 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -53,11 +53,6 @@ export const FeedItem = observer(function FeedItem({
       .toggleUpvote()
       .catch(e => console.error('Failed to toggle upvote', record, e))
   }
-  const onPressToggleDownvote = () => {
-    item
-      .toggleDownvote()
-      .catch(e => console.error('Failed to toggle downvote', record, e))
-  }
   const onDeletePost = () => {
     item.delete().then(
       () => {
@@ -150,14 +145,11 @@ export const FeedItem = observer(function FeedItem({
             replyCount={item.replyCount}
             repostCount={item.repostCount}
             upvoteCount={item.upvoteCount}
-            downvoteCount={item.downvoteCount}
             isReposted={!!item.myState.repost}
             isUpvoted={!!item.myState.upvote}
-            isDownvoted={!!item.myState.downvote}
             onPressReply={onPressReply}
             onPressToggleRepost={onPressToggleRepost}
             onPressToggleUpvote={onPressToggleUpvote}
-            onPressToggleDownvote={onPressToggleDownvote}
           />
         </View>
       </View>
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index 5a3743763..ed8924964 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -20,6 +20,7 @@ import {
 import {pluralize} from '../../lib/strings'
 import {s, colors} from '../../lib/styles'
 import {getGradient} from '../../lib/asset-gen'
+import {MagnifyingGlassIcon} from '../../lib/icons'
 import {DropdownBtn, DropdownItem} from '../util/DropdownBtn'
 import Toast from '../util/Toast'
 import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
@@ -43,10 +44,8 @@ export const ProfileHeader = observer(function ProfileHeader({
   const onPressBack = () => {
     store.nav.tab.goBack()
   }
-  const onPressMyAvatar = () => {
-    if (store.me.handle) {
-      store.nav.navigate(`/profile/${store.me.handle}`)
-    }
+  const onPressSearch = () => {
+    store.nav.navigate(`/search`)
   }
   const onPressToggleFollow = () => {
     view?.toggleFollowing().then(
@@ -117,15 +116,9 @@ export const ProfileHeader = observer(function ProfileHeader({
             />
           </TouchableOpacity>
         ) : undefined}
-        {store.me.did ? (
-          <TouchableOpacity style={styles.myAvatar} onPress={onPressMyAvatar}>
-            <UserAvatar
-              size={30}
-              handle={store.me.handle || ''}
-              displayName={store.me.displayName}
-            />
-          </TouchableOpacity>
-        ) : undefined}
+        <TouchableOpacity style={styles.searchBtn} onPress={onPressSearch}>
+          <MagnifyingGlassIcon size={19} style={styles.searchIcon} />
+        </TouchableOpacity>
         <View style={styles.avi}>
           <LoadingPlaceholder
             width={80}
@@ -194,15 +187,9 @@ export const ProfileHeader = observer(function ProfileHeader({
           />
         </TouchableOpacity>
       ) : undefined}
-      {store.me.did ? (
-        <TouchableOpacity style={styles.myAvatar} onPress={onPressMyAvatar}>
-          <UserAvatar
-            size={30}
-            handle={store.me.handle || ''}
-            displayName={store.me.displayName}
-          />
-        </TouchableOpacity>
-      ) : undefined}
+      <TouchableOpacity style={styles.searchBtn} onPress={onPressSearch}>
+        <MagnifyingGlassIcon size={19} style={styles.searchIcon} />
+      </TouchableOpacity>
       <View style={styles.avi}>
         <UserAvatar
           size={80}
@@ -375,14 +362,17 @@ const styles = StyleSheet.create({
     height: 14,
     color: colors.black,
   },
-  myAvatar: {
+  searchBtn: {
     position: 'absolute',
     top: 10,
     right: 12,
     backgroundColor: '#ffff',
-    padding: 1,
+    padding: 5,
     borderRadius: 30,
   },
+  searchIcon: {
+    color: colors.black,
+  },
   avi: {
     position: 'absolute',
     top: 80,
diff --git a/src/view/com/util/DropdownBtn.tsx b/src/view/com/util/DropdownBtn.tsx
index 99cc00bd2..01c9259a2 100644
--- a/src/view/com/util/DropdownBtn.tsx
+++ b/src/view/com/util/DropdownBtn.tsx
@@ -16,6 +16,7 @@ import {colors} from '../../lib/styles'
 import {toShareUrl} from '../../lib/strings'
 import {useStores} from '../../../state'
 import {ConfirmModel} from '../../../state/models/shell-ui'
+import {TABS_ENABLED} from '../../../build-flags'
 
 export interface DropdownItem {
   icon?: IconProp
@@ -84,13 +85,15 @@ export function PostDropdownBtn({
   const store = useStores()
 
   const dropdownItems: DropdownItem[] = [
-    {
-      icon: ['far', 'clone'],
-      label: 'Open in new tab',
-      onPress() {
-        store.nav.newTab(itemHref)
-      },
-    },
+    TABS_ENABLED
+      ? {
+          icon: ['far', 'clone'],
+          label: 'Open in new tab',
+          onPress() {
+            store.nav.newTab(itemHref)
+          },
+        }
+      : undefined,
     {
       icon: 'share',
       label: 'Share...',
diff --git a/src/view/com/util/LoadingPlaceholder.tsx b/src/view/com/util/LoadingPlaceholder.tsx
index c198407de..5ccd1bd14 100644
--- a/src/view/com/util/LoadingPlaceholder.tsx
+++ b/src/view/com/util/LoadingPlaceholder.tsx
@@ -9,7 +9,7 @@ import {
 } from 'react-native'
 import LinearGradient from 'react-native-linear-gradient'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {UpIcon, DownIcon} from '../../lib/icons'
+import {UpIcon} from '../../lib/icons'
 import {s, colors} from '../../lib/styles'
 
 export function LoadingPlaceholder({
@@ -93,18 +93,16 @@ export function PostLoadingPlaceholder({
             <FontAwesomeIcon
               style={s.gray3}
               icon={['far', 'comment']}
-              size={14}
+              size={16}
             />
           </View>
           <View style={s.flex1}>
-            <FontAwesomeIcon style={s.gray3} icon="retweet" size={18} />
+            <FontAwesomeIcon style={s.gray3} icon="retweet" size={20} />
           </View>
           <View style={s.flex1}>
-            <UpIcon style={s.gray3} size={18} />
-          </View>
-          <View style={s.flex1}>
-            <DownIcon style={s.gray3} size={18} />
+            <UpIcon style={s.gray3} size={19} strokeWidth={1.7} />
           </View>
+          <View style={s.flex1}></View>
         </View>
       </View>
     </View>
diff --git a/src/view/com/util/PostCtrls.tsx b/src/view/com/util/PostCtrls.tsx
index a3d2085e9..144351d85 100644
--- a/src/view/com/util/PostCtrls.tsx
+++ b/src/view/com/util/PostCtrls.tsx
@@ -8,27 +8,23 @@ import Animated, {
   interpolate,
 } from 'react-native-reanimated'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {UpIcon, UpIconSolid, DownIcon, DownIconSolid} from '../../lib/icons'
+import {UpIcon, UpIconSolid} from '../../lib/icons'
 import {s, colors} from '../../lib/styles'
 
 interface PostCtrlsOpts {
   replyCount: number
   repostCount: number
   upvoteCount: number
-  downvoteCount: number
   isReposted: boolean
   isUpvoted: boolean
-  isDownvoted: boolean
   onPressReply: () => void
   onPressToggleRepost: () => void
   onPressToggleUpvote: () => void
-  onPressToggleDownvote: () => void
 }
 
 export function PostCtrls(opts: PostCtrlsOpts) {
   const interp1 = useSharedValue<number>(0)
   const interp2 = useSharedValue<number>(0)
-  const interp3 = useSharedValue<number>(0)
 
   const anim1Style = useAnimatedStyle(() => ({
     transform: [{scale: interpolate(interp1.value, [0, 1.0], [1.0, 3.0])}],
@@ -38,10 +34,6 @@ export function PostCtrls(opts: PostCtrlsOpts) {
     transform: [{scale: interpolate(interp2.value, [0, 1.0], [1.0, 3.0])}],
     opacity: interpolate(interp2.value, [0, 1.0], [1.0, 0.0]),
   }))
-  const anim3Style = useAnimatedStyle(() => ({
-    transform: [{scale: interpolate(interp3.value, [0, 1.0], [1.0, 3.0])}],
-    opacity: interpolate(interp3.value, [0, 1.0], [1.0, 0.0]),
-  }))
 
   const onPressToggleRepostWrapper = () => {
     if (!opts.isReposted) {
@@ -59,14 +51,6 @@ export function PostCtrls(opts: PostCtrlsOpts) {
     }
     opts.onPressToggleUpvote()
   }
-  const onPressToggleDownvoteWrapper = () => {
-    if (!opts.isDownvoted) {
-      interp3.value = withTiming(1, {duration: 300}, () => {
-        interp3.value = withDelay(100, withTiming(0, {duration: 20}))
-      })
-    }
-    opts.onPressToggleDownvote()
-  }
 
   return (
     <View style={styles.ctrls}>
@@ -75,9 +59,9 @@ export function PostCtrls(opts: PostCtrlsOpts) {
           <FontAwesomeIcon
             style={styles.ctrlIcon}
             icon={['far', 'comment']}
-            size={14}
+            size={16}
           />
-          <Text style={[s.gray5, s.ml5, s.f13]}>{opts.replyCount}</Text>
+          <Text style={[s.gray5, s.ml5, s.f17]}>{opts.replyCount}</Text>
         </TouchableOpacity>
       </View>
       <View style={s.flex1}>
@@ -90,14 +74,14 @@ export function PostCtrls(opts: PostCtrlsOpts) {
                 opts.isReposted ? styles.ctrlIconReposted : styles.ctrlIcon
               }
               icon="retweet"
-              size={18}
+              size={20}
             />
           </Animated.View>
           <Text
             style={
               opts.isReposted
-                ? [s.bold, s.green3, s.f13, s.ml5]
-                : [s.gray5, s.f13, s.ml5]
+                ? [s.bold, s.green3, s.f17, s.ml5]
+                : [s.gray5, s.f17, s.ml5]
             }>
             {opts.repostCount}
           </Text>
@@ -109,42 +93,22 @@ export function PostCtrls(opts: PostCtrlsOpts) {
           onPress={onPressToggleUpvoteWrapper}>
           <Animated.View style={anim2Style}>
             {opts.isUpvoted ? (
-              <UpIconSolid style={styles.ctrlIconUpvoted} size={18} />
+              <UpIconSolid style={[styles.ctrlIconUpvoted]} size={19} />
             ) : (
-              <UpIcon style={styles.ctrlIcon} size={18} />
+              <UpIcon style={[styles.ctrlIcon]} size={20} strokeWidth={1.5} />
             )}
           </Animated.View>
           <Text
             style={
               opts.isUpvoted
-                ? [s.bold, s.red3, s.f13, s.ml5]
-                : [s.gray5, s.f13, s.ml5]
+                ? [s.bold, s.red3, s.f17, s.ml5]
+                : [s.gray5, s.f17, s.ml5]
             }>
             {opts.upvoteCount}
           </Text>
         </TouchableOpacity>
       </View>
-      <View style={s.flex1}>
-        <TouchableOpacity
-          style={styles.ctrl}
-          onPress={onPressToggleDownvoteWrapper}>
-          <Animated.View style={anim3Style}>
-            {opts.isDownvoted ? (
-              <DownIconSolid style={styles.ctrlIconDownvoted} size={18} />
-            ) : (
-              <DownIcon style={styles.ctrlIcon} size={18} />
-            )}
-          </Animated.View>
-          <Text
-            style={
-              opts.isDownvoted
-                ? [s.bold, s.blue3, s.f13, s.ml5]
-                : [s.gray5, s.f13, s.ml5]
-            }>
-            {opts.downvoteCount}
-          </Text>
-        </TouchableOpacity>
-      </View>
+      <View style={s.flex1}></View>
     </View>
   )
 }
@@ -152,12 +116,10 @@ export function PostCtrls(opts: PostCtrlsOpts) {
 const styles = StyleSheet.create({
   ctrls: {
     flexDirection: 'row',
-    paddingRight: 20,
   },
   ctrl: {
     flexDirection: 'row',
     alignItems: 'center',
-    paddingLeft: 4,
     paddingRight: 4,
   },
   ctrlIcon: {
@@ -169,7 +131,4 @@ const styles = StyleSheet.create({
   ctrlIconUpvoted: {
     color: colors.red3,
   },
-  ctrlIconDownvoted: {
-    color: colors.blue3,
-  },
 })
diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx
index 7e68bcd15..55a71ea26 100644
--- a/src/view/com/util/ViewHeader.tsx
+++ b/src/view/com/util/ViewHeader.tsx
@@ -3,6 +3,7 @@ import {StyleSheet, Text, TouchableOpacity, View} from 'react-native'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {UserAvatar} from './UserAvatar'
 import {colors} from '../../lib/styles'
+import {MagnifyingGlassIcon} from '../../lib/icons'
 import {useStores} from '../../../state'
 
 export function ViewHeader({
@@ -16,16 +17,14 @@ export function ViewHeader({
   const onPressBack = () => {
     store.nav.tab.goBack()
   }
-  const onPressAvatar = () => {
-    if (store.me.handle) {
-      store.nav.navigate(`/profile/${store.me.handle}`)
-    }
+  const onPressSearch = () => {
+    store.nav.navigate(`/search`)
   }
   return (
     <View style={styles.header}>
       {store.nav.tab.canGoBack ? (
         <TouchableOpacity onPress={onPressBack} style={styles.backIcon}>
-          <FontAwesomeIcon size={18} icon="angle-left" style={{marginTop: 3}} />
+          <FontAwesomeIcon size={18} icon="angle-left" style={{marginTop: 6}} />
         </TouchableOpacity>
       ) : (
         <View style={styles.cornerPlaceholder} />
@@ -38,17 +37,9 @@ export function ViewHeader({
           </Text>
         ) : undefined}
       </View>
-      {store.me.did ? (
-        <TouchableOpacity onPress={onPressAvatar}>
-          <UserAvatar
-            size={24}
-            handle={store.me.handle || ''}
-            displayName={store.me.displayName}
-          />
-        </TouchableOpacity>
-      ) : (
-        <View style={styles.cornerPlaceholder} />
-      )}
+      <TouchableOpacity onPress={onPressSearch} style={styles.searchBtn}>
+        <MagnifyingGlassIcon size={17} style={styles.searchBtnIcon} />
+      </TouchableOpacity>
     </View>
   )
 }
@@ -83,8 +74,22 @@ const styles = StyleSheet.create({
   },
 
   cornerPlaceholder: {
-    width: 24,
-    height: 24,
+    width: 30,
+    height: 30,
+  },
+  backIcon: {width: 30, height: 30},
+  searchBtn: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    justifyContent: 'center',
+    backgroundColor: colors.gray1,
+    width: 30,
+    height: 30,
+    borderRadius: 15,
+  },
+  searchBtnIcon: {
+    color: colors.black,
+    position: 'relative',
+    top: -1,
   },
-  backIcon: {width: 24, height: 24},
 })
diff --git a/src/view/lib/icons.tsx b/src/view/lib/icons.tsx
index c160df3cc..05b1ec601 100644
--- a/src/view/lib/icons.tsx
+++ b/src/view/lib/icons.tsx
@@ -91,7 +91,7 @@ export function HomeIconSolid({
 
 // Copyright (c) 2020 Refactoring UI Inc.
 // https://github.com/tailwindlabs/heroicons/blob/master/LICENSE
-export function MangifyingGlassIcon({
+export function MagnifyingGlassIcon({
   style,
   size,
 }: {
@@ -116,33 +116,6 @@ export function MangifyingGlassIcon({
   )
 }
 
-// Copyright (c) 2020 Refactoring UI Inc.
-// https://github.com/tailwindlabs/heroicons/blob/master/LICENSE
-export function MangifyingGlassIconSolid({
-  style,
-  size,
-}: {
-  style?: StyleProp<ViewStyle>
-  size?: string | number
-}) {
-  return (
-    <Svg
-      fill="none"
-      viewBox="0 0 24 24"
-      strokeWidth={3}
-      stroke="currentColor"
-      width={size || 24}
-      height={size || 24}
-      style={style}>
-      <Path
-        strokeLinecap="round"
-        strokeLinejoin="round"
-        d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"
-      />
-    </Svg>
-  )
-}
-
 // https://github.com/Remix-Design/RemixIcon/blob/master/License
 export function BellIcon({
   style,
@@ -221,9 +194,11 @@ export function UserGroupIcon({
 export function UpIcon({
   style,
   size,
+  strokeWidth = 1.3,
 }: {
   style?: StyleProp<ViewStyle>
   size?: string | number
+  strokeWidth: number
 }) {
   return (
     <Svg
@@ -232,8 +207,10 @@ export function UpIcon({
       height={size || 24}
       style={style}>
       <Path
-        strokeWidth={1.3}
+        strokeWidth={strokeWidth}
         stroke="currentColor"
+        strokeLinecap="round"
+        strokeLinejoin="round"
         d="M 7 3 L 2 8 L 4.5 8 L 4.5 11.5 L 9.5 11.5 L 9.5 8 L 12 8 L 7 3 Z"
       />
     </Svg>
@@ -257,6 +234,8 @@ export function UpIconSolid({
         strokeWidth={1.3}
         stroke="currentColor"
         fill="currentColor"
+        strokeLinecap="round"
+        strokeLinejoin="round"
         d="M 7 3 L 2 8 L 4.5 8 L 4.5 11.5 L 9.5 11.5 L 9.5 8 L 12 8 L 7 3 Z"
       />
     </Svg>
@@ -279,6 +258,8 @@ export function DownIcon({
       <Path
         strokeWidth={1.3}
         stroke="currentColor"
+        strokeLinecap="round"
+        strokeLinejoin="round"
         d="M 7 11.5 L 2 6.5 L 4.5 6.5 L 4.5 3 L 9.5 3 L 9.5 6.5 L 12 6.5 L 7 11.5 Z"
       />
     </Svg>
@@ -302,6 +283,8 @@ export function DownIconSolid({
         strokeWidth={1.3}
         stroke="currentColor"
         fill="currentColor"
+        strokeLinecap="round"
+        strokeLinejoin="round"
         d="M 7 11.5 L 2 6.5 L 4.5 6.5 L 4.5 3 L 9.5 3 L 9.5 6.5 L 12 6.5 L 7 11.5 Z"
       />
     </Svg>
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
index 609b1ca38..8dd7ca411 100644
--- a/src/view/screens/Home.tsx
+++ b/src/view/screens/Home.tsx
@@ -5,7 +5,6 @@ import useAppState from 'react-native-appstate-hook'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {ViewHeader} from '../com/util/ViewHeader'
 import {Feed} from '../com/posts/Feed'
-import {FAB} from '../com/util/FloatingActionButton'
 import {useStores} from '../../state'
 import {FeedModel} from '../../state/models/feed-view'
 import {ScreenParams} from '../routes'
@@ -65,7 +64,7 @@ export const Home = observer(function Home({
     }
   }, [visible, store])
 
-  const onComposePress = () => {
+  const onPressCompose = () => {
     store.shell.openComposer({onPost: onCreatePost})
   }
   const onCreatePost = () => {
@@ -87,6 +86,7 @@ export const Home = observer(function Home({
         feed={defaultFeedView}
         scrollElRef={scrollElRef}
         style={{flex: 1}}
+        onPressCompose={onPressCompose}
         onPressTryAgain={onPressTryAgain}
       />
       {defaultFeedView.hasNewLatest ? (
@@ -95,7 +95,6 @@ export const Home = observer(function Home({
           <Text style={styles.loadLatestText}>Load new posts</Text>
         </TouchableOpacity>
       ) : undefined}
-      <FAB icon="pen-nib" onPress={onComposePress} />
     </View>
   )
 })
diff --git a/src/view/screens/Notifications.tsx b/src/view/screens/Notifications.tsx
index 7e4de497e..1e7abdb90 100644
--- a/src/view/screens/Notifications.tsx
+++ b/src/view/screens/Notifications.tsx
@@ -1,7 +1,6 @@
 import React, {useState, useEffect} from 'react'
 import {View} from 'react-native'
 import {ViewHeader} from '../com/util/ViewHeader'
-import {FAB} from '../com/util/FloatingActionButton'
 import {Feed} from '../com/notifications/Feed'
 import {useStores} from '../../state'
 import {NotificationsViewModel} from '../../state/models/notifications-view'
@@ -37,9 +36,6 @@ export const Notifications = ({navIdx, visible}: ScreenParams) => {
     }
   }, [visible, store])
 
-  const onComposePress = () => {
-    store.shell.openComposer({})
-  }
   const onPressTryAgain = () => {
     notesView?.refresh()
   }
@@ -48,7 +44,6 @@ export const Notifications = ({navIdx, visible}: ScreenParams) => {
     <View style={{flex: 1}}>
       <ViewHeader title="Notifications" />
       {notesView && <Feed view={notesView} onPressTryAgain={onPressTryAgain} />}
-      <FAB icon="pen-nib" onPress={onComposePress} />
     </View>
   )
 }
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index e637c6ad8..1187e626e 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -3,7 +3,6 @@ import {StyleSheet, Text, View} from 'react-native'
 import {observer} from 'mobx-react-lite'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {ViewSelector} from '../com/util/ViewSelector'
-import {FAB} from '../com/util/FloatingActionButton'
 import {ScreenParams} from '../routes'
 import {ProfileUiModel, Sections} from '../../state/models/profile-ui'
 import {MembershipItem} from '../../state/models/memberships-view'
@@ -86,9 +85,6 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
       ),
     )
   }
-  const onComposePress = () => {
-    store.shell.openComposer({})
-  }
 
   // rendering
   // =
@@ -241,7 +237,6 @@ export const Profile = observer(({navIdx, visible, params}: ScreenParams) => {
       ) : (
         renderHeader()
       )}
-      <FAB icon="pen-nib" onPress={onComposePress} />
     </View>
   )
 })
diff --git a/src/view/shell/mobile/index.tsx b/src/view/shell/mobile/index.tsx
index e0f7c07aa..1c148b18c 100644
--- a/src/view/shell/mobile/index.tsx
+++ b/src/view/shell/mobile/index.tsx
@@ -26,6 +26,7 @@ import Animated, {
 } from 'react-native-reanimated'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {IconProp} from '@fortawesome/fontawesome-svg-core'
+import {TABS_ENABLED} from '../../../build-flags'
 import {useStores} from '../../../state'
 import {NavigationModel} from '../../../state/models/navigation'
 import {match, MatchResult} from '../../routes'
@@ -41,8 +42,6 @@ import {
   GridIconSolid,
   HomeIcon,
   HomeIconSolid,
-  MangifyingGlassIcon,
-  MangifyingGlassIconSolid,
   BellIcon,
   BellIconSolid,
 } from '../../lib/icons'
@@ -65,8 +64,6 @@ const Btn = ({
     | 'home-solid'
     | 'bell'
     | 'bell-solid'
-    | 'search'
-    | 'search-solid'
   notificationCount?: number
   tabCount?: number
   onPress?: (event: GestureResponderEvent) => void
@@ -85,14 +82,6 @@ const Btn = ({
   } else if (icon === 'home-solid') {
     IconEl = HomeIconSolid
     size = 24
-  } else if (icon === 'search') {
-    IconEl = MangifyingGlassIcon
-    size = 24
-    addedStyles = {position: 'relative', top: -1} as ViewStyle
-  } else if (icon === 'search-solid') {
-    IconEl = MangifyingGlassIconSolid
-    size = 24
-    addedStyles = {position: 'relative', top: -1} as ViewStyle
   } else if (icon === 'bell') {
     IconEl = BellIcon
     size = 24
@@ -147,7 +136,6 @@ export const MobileShell: React.FC = observer(() => {
       store.nav.navigate('/')
     }
   }
-  const onPressSearch = () => store.nav.navigate('/search')
   const onPressMenu = () => setMainMenuActive(true)
   const onPressNotifications = () => store.nav.navigate('/notifications')
   const onPressTabs = () => toggleTabsMenu(!isTabsSelectorActive)
@@ -261,7 +249,6 @@ export const MobileShell: React.FC = observer(() => {
   }
 
   const isAtHome = store.nav.tab.current.url === '/'
-  const isAtSearch = store.nav.tab.current.url === '/search'
   const isAtNotifications = store.nav.tab.current.url === '/notifications'
   return (
     <View style={styles.outerContainer}>
@@ -326,16 +313,13 @@ export const MobileShell: React.FC = observer(() => {
           onPress={onPressHome}
           onLongPress={doNewTab('/')}
         />
-        <Btn
-          icon={isAtSearch ? 'search-solid' : 'search'}
-          onPress={onPressSearch}
-          onLongPress={doNewTab('/search')}
-        />
-        <Btn
-          icon={isTabsSelectorActive ? 'clone' : ['far', 'clone']}
-          onPress={onPressTabs}
-          tabCount={store.nav.tabCount}
-        />
+        {TABS_ENABLED ? (
+          <Btn
+            icon={isTabsSelectorActive ? 'clone' : ['far', 'clone']}
+            onPress={onPressTabs}
+            tabCount={store.nav.tabCount}
+          />
+        ) : undefined}
         <Btn
           icon={isAtNotifications ? 'bell-solid' : 'bell'}
           onPress={onPressNotifications}