about summary refs log tree commit diff
path: root/src/view/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com')
-rw-r--r--src/view/com/composer/Prompt.tsx88
-rw-r--r--src/view/com/notifications/FeedItem.tsx16
-rw-r--r--src/view/com/post-thread/PostThread.tsx2
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx31
-rw-r--r--src/view/com/post/Post.tsx174
-rw-r--r--src/view/com/posts/FeedItem.tsx34
-rw-r--r--src/view/com/util/PostMuted.tsx50
-rw-r--r--src/view/com/util/Toast.tsx84
-rw-r--r--src/view/com/util/UserInfoText.tsx8
9 files changed, 262 insertions, 225 deletions
diff --git a/src/view/com/composer/Prompt.tsx b/src/view/com/composer/Prompt.tsx
index 46a0cec62..88d5de2bf 100644
--- a/src/view/com/composer/Prompt.tsx
+++ b/src/view/com/composer/Prompt.tsx
@@ -1,91 +1,45 @@
 import React from 'react'
-import {StyleSheet, TouchableOpacity, View} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {StyleSheet, TouchableOpacity} from 'react-native'
+import {UserAvatar} from '../util/UserAvatar'
 import {Text} from '../util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useStores} from 'state/index'
 
 export function ComposePrompt({
-  text = "What's up?",
-  btn = 'Post',
-  isReply = false,
   onPressCompose,
 }: {
-  text?: string
-  btn?: string
-  isReply?: boolean
   onPressCompose: (imagesOpen?: boolean) => void
 }) {
+  const store = useStores()
   const pal = usePalette('default')
   return (
     <TouchableOpacity
-      testID="composePromptButton"
-      style={[
-        pal.view,
-        pal.border,
-        styles.container,
-        isReply ? styles.containerReply : undefined,
-      ]}
+      testID="replyPromptBtn"
+      style={[pal.view, pal.border, styles.prompt]}
       onPress={() => onPressCompose()}>
-      {!isReply && (
-        <FontAwesomeIcon
-          icon={['fas', 'pen-nib']}
-          size={18}
-          style={[pal.textLight, styles.iconLeft]}
-        />
-      )}
-      <View style={styles.textContainer}>
-        <Text type={isReply ? 'lg' : 'lg-medium'} style={pal.textLight}>
-          {text}
-        </Text>
-      </View>
-      {isReply ? (
-        <View
-          style={[styles.btn, {backgroundColor: pal.colors.backgroundLight}]}>
-          <Text type="button" style={pal.textLight}>
-            {btn}
-          </Text>
-        </View>
-      ) : (
-        <TouchableOpacity onPress={() => onPressCompose(true)}>
-          <FontAwesomeIcon
-            icon={['far', 'image']}
-            size={18}
-            style={[pal.textLight, styles.iconRight]}
-          />
-        </TouchableOpacity>
-      )}
+      <UserAvatar
+        handle={store.me.handle}
+        avatar={store.me.avatar}
+        displayName={store.me.displayName}
+        size={38}
+      />
+      <Text type="xl" style={[pal.text, styles.label]}>
+        Write your reply
+      </Text>
     </TouchableOpacity>
   )
 }
 
 const styles = StyleSheet.create({
-  iconLeft: {
-    marginLeft: 22,
-    marginRight: 2,
-  },
-  iconRight: {
-    marginRight: 20,
-  },
-  container: {
-    paddingVertical: 16,
+  prompt: {
+    paddingHorizontal: 20,
+    paddingTop: 10,
+    paddingBottom: 10,
     flexDirection: 'row',
     alignItems: 'center',
     borderTopWidth: 1,
   },
-  containerReply: {
-    paddingVertical: 14,
-    paddingHorizontal: 10,
-  },
-  avatar: {
-    width: 50,
-  },
-  textContainer: {
-    marginLeft: 10,
-    flex: 1,
-  },
-  btn: {
-    paddingVertical: 6,
-    paddingHorizontal: 14,
-    borderRadius: 30,
+  label: {
+    paddingLeft: 12,
   },
 })
diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx
index 68f12b721..acd00a67d 100644
--- a/src/view/com/notifications/FeedItem.tsx
+++ b/src/view/com/notifications/FeedItem.tsx
@@ -90,10 +90,10 @@ export const FeedItem = observer(function FeedItem({
           style={
             item.isRead
               ? undefined
-              : [
-                  styles.outerUnread,
-                  {backgroundColor: pal.colors.unreadNotifBg},
-                ]
+              : {
+                  backgroundColor: pal.colors.unreadNotifBg,
+                  borderColor: pal.colors.unreadNotifBorder,
+                }
           }
         />
       </Link>
@@ -152,7 +152,10 @@ export const FeedItem = observer(function FeedItem({
         pal.border,
         item.isRead
           ? undefined
-          : [styles.outerUnread, {backgroundColor: pal.colors.unreadNotifBg}],
+          : {
+              backgroundColor: pal.colors.unreadNotifBg,
+              borderColor: pal.colors.unreadNotifBorder,
+            },
       ]}
       href={itemHref}
       title={itemTitle}
@@ -391,9 +394,6 @@ const styles = StyleSheet.create({
     paddingRight: 15,
     borderTopWidth: 1,
   },
-  outerUnread: {
-    borderColor: colors.blue1,
-  },
   layout: {
     flexDirection: 'row',
   },
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index a417012b0..646d4b276 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -96,7 +96,7 @@ export const PostThread = observer(function PostThread({
       onLayout={onLayout}
       onScrollToIndexFailed={onScrollToIndexFailed}
       style={s.hContentRegion}
-      contentContainerStyle={s.contentContainer}
+      contentContainerStyle={s.contentContainerExtra}
     />
   )
 })
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 8eda0962a..1413148a9 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -21,8 +21,8 @@ import {useStores} from 'state/index'
 import {PostMeta} from '../util/PostMeta'
 import {PostEmbeds} from '../util/PostEmbeds'
 import {PostCtrls} from '../util/PostCtrls'
+import {PostMutedWrapper} from '../util/PostMuted'
 import {ErrorMessage} from '../util/error/ErrorMessage'
-import {ComposePrompt} from '../composer/Prompt'
 import {usePalette} from 'lib/hooks/usePalette'
 
 const PARENT_REPLY_LINE_LENGTH = 8
@@ -271,23 +271,17 @@ export const PostThreadItem = observer(function PostThreadItem({
             </View>
           </View>
         </View>
-        <ComposePrompt
-          isReply
-          text="Write your reply"
-          btn="Reply"
-          onPressCompose={onPressReply}
-        />
       </>
     )
   } else {
     return (
-      <>
+      <PostMutedWrapper isMuted={item.post.author.viewer?.muted === true}>
         <Link
           style={[styles.outer, {borderTopColor: pal.colors.border}, pal.view]}
           href={itemHref}
           title={itemTitle}
           noFeedback>
-          {record.reply && (
+          {item._showParentReplyLine && (
             <View
               style={[
                 styles.parentReplyLine,
@@ -295,7 +289,7 @@ export const PostThreadItem = observer(function PostThreadItem({
               ]}
             />
           )}
-          {item.replies?.length !== 0 && (
+          {item._showChildReplyLine && (
             <View
               style={[
                 styles.childReplyLine,
@@ -322,12 +316,7 @@ export const PostThreadItem = observer(function PostThreadItem({
                 did={item.post.author.did}
                 declarationCid={item.post.author.declaration.cid}
               />
-              {item.post.author.viewer?.muted ? (
-                <View style={[styles.mutedWarning, pal.btn]}>
-                  <FontAwesomeIcon icon={['far', 'eye-slash']} style={s.mr2} />
-                  <Text type="sm">This post is by a muted account.</Text>
-                </View>
-              ) : item.richText?.text ? (
+              {item.richText?.text ? (
                 <View style={styles.postTextContainer}>
                   <RichText
                     type="post-text"
@@ -384,7 +373,7 @@ export const PostThreadItem = observer(function PostThreadItem({
             />
           </Link>
         ) : undefined}
-      </>
+      </PostMutedWrapper>
     )
   }
 })
@@ -441,14 +430,6 @@ const styles = StyleSheet.create({
     paddingRight: 5,
     maxWidth: 240,
   },
-  mutedWarning: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    padding: 10,
-    marginTop: 2,
-    marginBottom: 6,
-    borderRadius: 2,
-  },
   postTextContainer: {
     flexDirection: 'row',
     alignItems: 'center',
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index bf8dfed05..7b4161afc 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -17,6 +17,7 @@ import {UserInfoText} from '../util/UserInfoText'
 import {PostMeta} from '../util/PostMeta'
 import {PostEmbeds} from '../util/PostEmbeds'
 import {PostCtrls} from '../util/PostCtrls'
+import {PostMutedWrapper} from '../util/PostMuted'
 import {Text} from '../util/text/Text'
 import {RichText} from '../util/text/RichText'
 import * as Toast from '../util/Toast'
@@ -140,92 +141,89 @@ export const Post = observer(function Post({
   }
 
   return (
-    <Link
-      style={[styles.outer, pal.view, pal.border, style]}
-      href={itemHref}
-      title={itemTitle}
-      noFeedback>
-      {showReplyLine && <View style={styles.replyLine} />}
-      <View style={styles.layout}>
-        <View style={styles.layoutAvi}>
-          <Link href={authorHref} title={authorTitle}>
-            <UserAvatar
-              size={52}
-              displayName={item.post.author.displayName}
-              handle={item.post.author.handle}
-              avatar={item.post.author.avatar}
-            />
-          </Link>
-        </View>
-        <View style={styles.layoutContent}>
-          <PostMeta
-            authorHandle={item.post.author.handle}
-            authorDisplayName={item.post.author.displayName}
-            timestamp={item.post.indexedAt}
-            did={item.post.author.did}
-            declarationCid={item.post.author.declaration.cid}
-          />
-          {replyAuthorDid !== '' && (
-            <View style={[s.flexRow, s.mb2, s.alignCenter]}>
-              <FontAwesomeIcon
-                icon="reply"
-                size={9}
-                style={[pal.textLight, s.mr5]}
-              />
-              <Text type="sm" style={[pal.textLight, s.mr2]} lineHeight={1.2}>
-                Reply to
-              </Text>
-              <UserInfoText
-                type="sm"
-                did={replyAuthorDid}
-                attr="displayName"
-                style={[pal.textLight]}
+    <PostMutedWrapper isMuted={item.post.author.viewer?.muted === true}>
+      <Link
+        style={[styles.outer, pal.view, pal.border, style]}
+        href={itemHref}
+        title={itemTitle}
+        noFeedback>
+        {showReplyLine && <View style={styles.replyLine} />}
+        <View style={styles.layout}>
+          <View style={styles.layoutAvi}>
+            <Link href={authorHref} title={authorTitle}>
+              <UserAvatar
+                size={52}
+                displayName={item.post.author.displayName}
+                handle={item.post.author.handle}
+                avatar={item.post.author.avatar}
               />
-            </View>
-          )}
-          {item.post.author.viewer?.muted ? (
-            <View style={[styles.mutedWarning, pal.btn]}>
-              <FontAwesomeIcon icon={['far', 'eye-slash']} style={s.mr2} />
-              <Text type="sm">This post is by a muted account.</Text>
-            </View>
-          ) : item.richText?.text ? (
-            <View style={styles.postTextContainer}>
-              <RichText
-                type="post-text"
-                richText={item.richText}
-                lineHeight={1.3}
-              />
-            </View>
-          ) : undefined}
-          <PostEmbeds embed={item.post.embed} style={s.mb10} />
-          <PostCtrls
-            itemUri={itemUri}
-            itemCid={itemCid}
-            itemHref={itemHref}
-            itemTitle={itemTitle}
-            author={{
-              avatar: item.post.author.avatar!,
-              handle: item.post.author.handle,
-              displayName: item.post.author.displayName!,
-            }}
-            indexedAt={item.post.indexedAt}
-            text={item.richText?.text || record.text}
-            isAuthor={item.post.author.did === store.me.did}
-            replyCount={item.post.replyCount}
-            repostCount={item.post.repostCount}
-            upvoteCount={item.post.upvoteCount}
-            isReposted={!!item.post.viewer.repost}
-            isUpvoted={!!item.post.viewer.upvote}
-            onPressReply={onPressReply}
-            onPressToggleRepost={onPressToggleRepost}
-            onPressToggleUpvote={onPressToggleUpvote}
-            onCopyPostText={onCopyPostText}
-            onOpenTranslate={onOpenTranslate}
-            onDeletePost={onDeletePost}
-          />
+            </Link>
+          </View>
+          <View style={styles.layoutContent}>
+            <PostMeta
+              authorHandle={item.post.author.handle}
+              authorDisplayName={item.post.author.displayName}
+              timestamp={item.post.indexedAt}
+              did={item.post.author.did}
+              declarationCid={item.post.author.declaration.cid}
+            />
+            {replyAuthorDid !== '' && (
+              <View style={[s.flexRow, s.mb2, s.alignCenter]}>
+                <FontAwesomeIcon
+                  icon="reply"
+                  size={9}
+                  style={[pal.textLight, s.mr5]}
+                />
+                <Text type="sm" style={[pal.textLight, s.mr2]} lineHeight={1.2}>
+                  Reply to
+                </Text>
+                <UserInfoText
+                  type="sm"
+                  did={replyAuthorDid}
+                  attr="displayName"
+                  style={[pal.textLight]}
+                />
+              </View>
+            )}
+            {item.richText?.text ? (
+              <View style={styles.postTextContainer}>
+                <RichText
+                  type="post-text"
+                  richText={item.richText}
+                  lineHeight={1.3}
+                />
+              </View>
+            ) : undefined}
+            <PostEmbeds embed={item.post.embed} style={s.mb10} />
+            <PostCtrls
+              itemUri={itemUri}
+              itemCid={itemCid}
+              itemHref={itemHref}
+              itemTitle={itemTitle}
+              author={{
+                avatar: item.post.author.avatar!,
+                handle: item.post.author.handle,
+                displayName: item.post.author.displayName!,
+              }}
+              indexedAt={item.post.indexedAt}
+              text={item.richText?.text || record.text}
+              isAuthor={item.post.author.did === store.me.did}
+              replyCount={item.post.replyCount}
+              repostCount={item.post.repostCount}
+              upvoteCount={item.post.upvoteCount}
+              isReposted={!!item.post.viewer.repost}
+              isUpvoted={!!item.post.viewer.upvote}
+              onPressReply={onPressReply}
+              onPressToggleRepost={onPressToggleRepost}
+              onPressToggleUpvote={onPressToggleUpvote}
+              onCopyPostText={onCopyPostText}
+              onOpenTranslate={onOpenTranslate}
+              onDeletePost={onDeletePost}
+            />
+          </View>
         </View>
-      </View>
-    </Link>
+      </Link>
+    </PostMutedWrapper>
   )
 })
 
@@ -245,14 +243,6 @@ const styles = StyleSheet.create({
   layoutContent: {
     flex: 1,
   },
-  mutedWarning: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    padding: 10,
-    marginTop: 2,
-    marginBottom: 6,
-    borderRadius: 2,
-  },
   postTextContainer: {
     flexDirection: 'row',
     alignItems: 'center',
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index 1006645a9..8b9a6eb2c 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -15,6 +15,7 @@ import {UserInfoText} from '../util/UserInfoText'
 import {PostMeta} from '../util/PostMeta'
 import {PostCtrls} from '../util/PostCtrls'
 import {PostEmbeds} from '../util/PostEmbeds'
+import {PostMutedWrapper} from '../util/PostMuted'
 import {RichText} from '../util/text/RichText'
 import * as Toast from '../util/Toast'
 import {UserAvatar} from '../util/UserAvatar'
@@ -113,6 +114,8 @@ export const FeedItem = observer(function ({
     item._isThreadChild || (!item.reason && !item._hideParent && item.reply)
   const isSmallTop = isChild && item._isThreadChild
   const isNoTop = isChild && !item._isThreadChild
+  const isMuted =
+    item.post.author.viewer?.muted && ignoreMuteFor !== item.post.author.did
   const outerStyles = [
     styles.outer,
     pal.view,
@@ -123,7 +126,7 @@ export const FeedItem = observer(function ({
   ]
 
   return (
-    <>
+    <PostMutedWrapper isMuted={isMuted}>
       {isChild && !item._isThreadChild && item.replyParent ? (
         <FeedItem
           item={item.replyParent}
@@ -160,7 +163,11 @@ export const FeedItem = observer(function ({
                 {color: pal.colors.textLight} as FontAwesomeIconStyle,
               ]}
             />
-            <Text type="sm-bold" style={pal.textLight} lineHeight={1.2}>
+            <Text
+              type="sm-bold"
+              style={pal.textLight}
+              lineHeight={1.2}
+              numberOfLines={1}>
               Reposted by{' '}
               {item.reasonRepost.by.displayName || item.reasonRepost.by.handle}
             </Text>
@@ -207,13 +214,7 @@ export const FeedItem = observer(function ({
                 />
               </View>
             )}
-            {item.post.author.viewer?.muted &&
-            ignoreMuteFor !== item.post.author.did ? (
-              <View style={[styles.mutedWarning, pal.btn]}>
-                <FontAwesomeIcon icon={['far', 'eye-slash']} style={s.mr2} />
-                <Text type="sm">This post is by a muted account.</Text>
-              </View>
-            ) : item.richText?.text ? (
+            {item.richText?.text ? (
               <View style={styles.postTextContainer}>
                 <RichText
                   type="post-text"
@@ -222,9 +223,7 @@ export const FeedItem = observer(function ({
                 />
               </View>
             ) : undefined}
-            {item.post.embed ? (
-              <PostEmbeds embed={item.post.embed} style={styles.embed} />
-            ) : null}
+            <PostEmbeds embed={item.post.embed} style={styles.embed} />
             <PostCtrls
               style={styles.ctrls}
               itemUri={itemUri}
@@ -280,7 +279,7 @@ export const FeedItem = observer(function ({
           </Text>
         </Link>
       ) : undefined}
-    </>
+    </PostMutedWrapper>
   )
 })
 
@@ -319,6 +318,7 @@ const styles = StyleSheet.create({
   includeReason: {
     flexDirection: 'row',
     paddingLeft: 50,
+    paddingRight: 20,
     marginTop: 2,
     marginBottom: 2,
   },
@@ -336,14 +336,6 @@ const styles = StyleSheet.create({
   layoutContent: {
     flex: 1,
   },
-  mutedWarning: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    padding: 10,
-    marginTop: 2,
-    marginBottom: 6,
-    borderRadius: 2,
-  },
   postTextContainer: {
     flexDirection: 'row',
     alignItems: 'center',
diff --git a/src/view/com/util/PostMuted.tsx b/src/view/com/util/PostMuted.tsx
new file mode 100644
index 000000000..d8573bd56
--- /dev/null
+++ b/src/view/com/util/PostMuted.tsx
@@ -0,0 +1,50 @@
+import React from 'react'
+import {StyleSheet, TouchableOpacity, View} from 'react-native'
+import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
+import {usePalette} from 'lib/hooks/usePalette'
+import {Text} from './text/Text'
+
+export function PostMutedWrapper({
+  isMuted,
+  children,
+}: React.PropsWithChildren<{isMuted: boolean}>) {
+  const pal = usePalette('default')
+  const [override, setOverride] = React.useState(false)
+  if (!isMuted || override) {
+    return <>{children}</>
+  }
+  return (
+    <View style={[styles.container, pal.view, pal.border]}>
+      <FontAwesomeIcon
+        icon={['far', 'eye-slash']}
+        style={[styles.icon, pal.text]}
+      />
+      <Text type="md" style={pal.textLight}>
+        Post from an account you muted.
+      </Text>
+      <TouchableOpacity
+        style={styles.showBtn}
+        onPress={() => setOverride(true)}>
+        <Text type="md" style={pal.link}>
+          Show post
+        </Text>
+      </TouchableOpacity>
+    </View>
+  )
+}
+
+const styles = StyleSheet.create({
+  container: {
+    flexDirection: 'row',
+    alignItems: 'center',
+    paddingVertical: 14,
+    paddingHorizontal: 18,
+    borderTopWidth: 1,
+  },
+  icon: {
+    marginRight: 10,
+  },
+  showBtn: {
+    marginLeft: 'auto',
+  },
+})
diff --git a/src/view/com/util/Toast.tsx b/src/view/com/util/Toast.tsx
index 197f47422..34a461f82 100644
--- a/src/view/com/util/Toast.tsx
+++ b/src/view/com/util/Toast.tsx
@@ -1,11 +1,81 @@
-import Toast from 'react-native-root-toast'
+import RootSiblings from 'react-native-root-siblings'
+import React from 'react'
+import {Animated, StyleSheet, View} from 'react-native'
+import {Text} from './text/Text'
+import {colors} from 'lib/styles'
+import {useTheme} from 'lib/ThemeContext'
+import {usePalette} from 'lib/hooks/usePalette'
+import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
+
+const TIMEOUT = 4e3
 
 export function show(message: string) {
-  Toast.show(message, {
-    duration: Toast.durations.LONG,
-    position: 50,
-    shadow: true,
-    animation: true,
-    hideOnPress: true,
+  const item = new RootSiblings(<Toast message={message} />)
+  setTimeout(() => {
+    item.destroy()
+  }, TIMEOUT)
+}
+
+function Toast({message}: {message: string}) {
+  const theme = useTheme()
+  const pal = usePalette('default')
+  const interp = useAnimatedValue(0)
+
+  React.useEffect(() => {
+    Animated.sequence([
+      Animated.timing(interp, {
+        toValue: 1,
+        duration: 150,
+        useNativeDriver: true,
+      }),
+      Animated.delay(3700),
+      Animated.timing(interp, {
+        toValue: 0,
+        duration: 150,
+        useNativeDriver: true,
+      }),
+    ]).start()
   })
+
+  const opacityStyle = {opacity: interp}
+  return (
+    <View style={styles.container}>
+      <Animated.View
+        style={[
+          pal.view,
+          pal.border,
+          styles.toast,
+          theme.colorScheme === 'dark' && styles.toastDark,
+          opacityStyle,
+        ]}>
+        <Text type="lg-medium" style={pal.text}>
+          {message}
+        </Text>
+      </Animated.View>
+    </View>
+  )
 }
+
+const styles = StyleSheet.create({
+  container: {
+    position: 'absolute',
+    top: 60,
+    left: 0,
+    right: 0,
+    alignItems: 'center',
+  },
+  toast: {
+    paddingHorizontal: 18,
+    paddingVertical: 10,
+    borderRadius: 24,
+    borderWidth: 1,
+    shadowColor: '#000',
+    shadowOpacity: 0.1,
+    shadowOffset: {width: 0, height: 4},
+    marginHorizontal: 6,
+  },
+  toastDark: {
+    backgroundColor: colors.gray6,
+    shadowOpacity: 0.5,
+  },
+})
diff --git a/src/view/com/util/UserInfoText.tsx b/src/view/com/util/UserInfoText.tsx
index 2655232fc..84170b3bf 100644
--- a/src/view/com/util/UserInfoText.tsx
+++ b/src/view/com/util/UserInfoText.tsx
@@ -58,15 +58,15 @@ export function UserInfoText({
   let inner
   if (didFail) {
     inner = (
-      <Text type={type} style={style}>
+      <Text type={type} style={style} numberOfLines={1}>
         {failed}
       </Text>
     )
   } else if (profile) {
     inner = (
-      <Text type={type} style={style} lineHeight={1.2}>{`${prefix || ''}${
-        profile[attr] || profile.handle
-      }`}</Text>
+      <Text type={type} style={style} lineHeight={1.2} numberOfLines={1}>{`${
+        prefix || ''
+      }${profile[attr] || profile.handle}`}</Text>
     )
   } else {
     inner = (