about summary refs log tree commit diff
path: root/src/view/com/composer
diff options
context:
space:
mode:
Diffstat (limited to 'src/view/com/composer')
-rw-r--r--src/view/com/composer/ComposePost.tsx136
-rw-r--r--src/view/com/composer/Prompt.tsx40
2 files changed, 111 insertions, 65 deletions
diff --git a/src/view/com/composer/ComposePost.tsx b/src/view/com/composer/ComposePost.tsx
index 10305adb6..ce42ee17e 100644
--- a/src/view/com/composer/ComposePost.tsx
+++ b/src/view/com/composer/ComposePost.tsx
@@ -1,4 +1,4 @@
-import React, {useEffect, useMemo, useState} from 'react'
+import React, {useEffect, useMemo, useRef, useState} from 'react'
 import {observer} from 'mobx-react-lite'
 import {
   ActivityIndicator,
@@ -17,9 +17,10 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {UserAutocompleteViewModel} from '../../../state/models/user-autocomplete-view'
 import {UserLocalPhotosModel} from '../../../state/models/user-local-photos'
 import {Autocomplete} from './Autocomplete'
-import Toast from '../util/Toast'
+import * as Toast from '../util/Toast'
 import ProgressCircle from '../util/ProgressCircle'
 import {TextLink} from '../util/Link'
+import {UserAvatar} from '../util/UserAvatar'
 import {useStores} from '../../../state'
 import * as apilib from '../../../state/lib/api'
 import {ComposerOpts} from '../../../state/models/shell-ui'
@@ -28,7 +29,6 @@ import {detectLinkables} from '../../../lib/strings'
 import {openPicker, openCamera} from 'react-native-image-crop-picker'
 
 const MAX_TEXT_LENGTH = 256
-const WARNING_TEXT_LENGTH = 200
 const DANGER_TEXT_LENGTH = MAX_TEXT_LENGTH
 
 export const ComposePost = observer(function ComposePost({
@@ -41,6 +41,7 @@ export const ComposePost = observer(function ComposePost({
   onClose: () => void
 }) {
   const store = useStores()
+  const textInput = useRef<TextInput>(null)
   const [isProcessing, setIsProcessing] = useState(false)
   const [error, setError] = useState('')
   const [text, setText] = useState('')
@@ -57,6 +58,22 @@ export const ComposePost = observer(function ComposePost({
   useEffect(() => {
     autocompleteView.setup()
   })
+  useEffect(() => {
+    // HACK
+    // wait a moment before focusing the input to resolve some layout bugs with the keyboard-avoiding-view
+    // -prf
+    let to: NodeJS.Timeout | undefined
+    if (textInput.current) {
+      to = setTimeout(() => {
+        textInput.current?.focus()
+      }, 250)
+    }
+    return () => {
+      if (to) {
+        clearTimeout(to)
+      }
+    }
+  }, [textInput.current])
 
   useEffect(() => {
     localPhotos.setup()
@@ -90,7 +107,10 @@ export const ComposePost = observer(function ComposePost({
     }
     setIsProcessing(true)
     try {
-      await apilib.post(store, text, replyTo, autocompleteView.knownHandles)
+      const replyRef = replyTo
+        ? {uri: replyTo.uri, cid: replyTo.cid}
+        : undefined
+      await apilib.post(store, text, replyRef, autocompleteView.knownHandles)
     } catch (e: any) {
       console.error(`Failed to create post: ${e.toString()}`)
       setError(
@@ -101,13 +121,7 @@ export const ComposePost = observer(function ComposePost({
     }
     onPost?.()
     onClose()
-    Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`, {
-      duration: Toast.durations.LONG,
-      position: Toast.positions.TOP,
-      shadow: true,
-      animation: true,
-      hideOnPress: true,
-    })
+    Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`)
   }
   const onSelectAutocompleteItem = (item: string) => {
     setText(replaceTextAutocompletePrefix(text, item))
@@ -115,12 +129,7 @@ export const ComposePost = observer(function ComposePost({
   }
 
   const canPost = text.length <= MAX_TEXT_LENGTH
-  const progressColor =
-    text.length > DANGER_TEXT_LENGTH
-      ? '#e60000'
-      : text.length > WARNING_TEXT_LENGTH
-      ? '#f7c600'
-      : undefined
+  const progressColor = text.length > DANGER_TEXT_LENGTH ? '#e60000' : undefined
 
   const textDecorated = useMemo(() => {
     let i = 0
@@ -142,7 +151,7 @@ export const ComposePost = observer(function ComposePost({
       <SafeAreaView style={s.flex1}>
         <View style={styles.topbar}>
           <TouchableOpacity onPress={onPressCancel}>
-            <Text style={[s.blue3, s.f16]}>Cancel</Text>
+            <Text style={[s.blue3, s.f18]}>Cancel</Text>
           </TouchableOpacity>
           <View style={s.flex1} />
           {isProcessing ? (
@@ -156,7 +165,9 @@ export const ComposePost = observer(function ComposePost({
                 start={{x: 0, y: 0}}
                 end={{x: 1, y: 1}}
                 style={styles.postBtn}>
-                <Text style={[s.white, s.f16, s.bold]}>Post</Text>
+                <Text style={[s.white, s.f16, s.bold]}>
+                  {replyTo ? 'Reply' : 'Post'}
+                </Text>
               </LinearGradient>
             </TouchableOpacity>
           ) : (
@@ -178,39 +189,46 @@ export const ComposePost = observer(function ComposePost({
           </View>
         )}
         {replyTo ? (
-          <View>
-            <Text style={s.gray4}>
-              Replying to{' '}
+          <View style={styles.replyToLayout}>
+            <UserAvatar
+              handle={replyTo.author.handle}
+              displayName={replyTo.author.displayName}
+              size={50}
+            />
+            <View style={styles.replyToPost}>
               <TextLink
                 href={`/profile/${replyTo.author.handle}`}
-                text={'@' + replyTo.author.handle}
-                style={[s.bold, s.gray5]}
+                text={replyTo.author.displayName || replyTo.author.handle}
+                style={[s.f16, s.bold]}
               />
-            </Text>
-            <View style={styles.replyToPost}>
-              <Text style={s.gray5}>{replyTo.text}</Text>
+              <Text style={[s.f16, s['lh16-1.3']]} numberOfLines={6}>
+                {replyTo.text}
+              </Text>
             </View>
           </View>
         ) : undefined}
-        <TextInput
-          multiline
-          scrollEnabled
-          onChangeText={(text: string) => onChangeText(text)}
-          placeholder={
-            replyTo
-              ? 'Write your reply'
-              : photoUris.length === 0
-              ? "What's up?"
-              : 'Add a comment...'
-          }
-          style={styles.textInput}>
-          {textDecorated}
-        </TextInput>
+        <View style={styles.textInputLayout}>
+          <UserAvatar
+            handle={store.me.handle || ''}
+            displayName={store.me.displayName}
+            size={50}
+          />
+          <TextInput
+            ref={textInput}
+            multiline
+            scrollEnabled
+            onChangeText={(text: string) => onChangeText(text)}
+            placeholder={replyTo ? 'Write your reply' : "What's up?"}
+            style={styles.textInput}>
+            {textDecorated}
+          </TextInput>
+        </View>
         {photoUris.length !== 0 && (
           <View style={styles.selectedImageContainer}>
             {photoUris.length !== 0 &&
-              photoUris.map(item => (
+              photoUris.map((item, index) => (
                 <View
+                  key={`selected-image-${index}`}
                   style={[
                     styles.selectedImage,
                     photoUris.length === 1
@@ -264,8 +282,9 @@ export const ComposePost = observer(function ComposePost({
                 style={{color: colors.blue3}}
               />
             </TouchableOpacity>
-            {localPhotos.photos.map(item => (
+            {localPhotos.photos.map((item, index) => (
               <TouchableOpacity
+                key={`local-image-${index}`}
                 style={styles.photoButton}
                 onPress={() => {
                   setPhotoUris([item.node.image.uri, ...photoUris])
@@ -343,9 +362,9 @@ const styles = StyleSheet.create({
     flexDirection: 'row',
     alignItems: 'center',
     paddingTop: 10,
-    paddingBottom: 5,
+    paddingBottom: 10,
     paddingHorizontal: 5,
-    height: 50,
+    height: 55,
   },
   postBtn: {
     borderRadius: 20,
@@ -371,19 +390,30 @@ const styles = StyleSheet.create({
     justifyContent: 'center',
     marginRight: 5,
   },
+  textInputLayout: {
+    flexDirection: 'row',
+    flex: 1,
+    borderTopWidth: 1,
+    borderTopColor: colors.gray2,
+    paddingTop: 16,
+  },
   textInput: {
     flex: 1,
     padding: 5,
-    fontSize: 21,
+    fontSize: 18,
+    marginLeft: 8,
+  },
+  replyToLayout: {
+    flexDirection: 'row',
+    borderTopWidth: 1,
+    borderTopColor: colors.gray2,
+    paddingTop: 16,
+    paddingBottom: 16,
   },
   replyToPost: {
-    paddingHorizontal: 8,
-    paddingVertical: 6,
-    borderWidth: 1,
-    borderColor: colors.gray2,
-    borderRadius: 6,
-    marginTop: 5,
-    marginBottom: 10,
+    flex: 1,
+    paddingLeft: 13,
+    paddingRight: 8,
   },
   contentCenter: {alignItems: 'center'},
   selectedImageContainer: {
diff --git a/src/view/com/composer/Prompt.tsx b/src/view/com/composer/Prompt.tsx
index f9fd7e7d3..7805e00dd 100644
--- a/src/view/com/composer/Prompt.tsx
+++ b/src/view/com/composer/Prompt.tsx
@@ -1,29 +1,42 @@
 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}) {
+export function ComposePrompt({
+  noAvi = false,
+  text = "What's up?",
+  btn = 'Post',
+  onPressCompose,
+}: {
+  noAvi?: boolean
+  text?: string
+  btn?: string
+  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>
+    <TouchableOpacity
+      style={[styles.container, noAvi ? styles.noAviContainer : undefined]}
+      onPress={onPressCompose}>
+      {!noAvi ? (
+        <TouchableOpacity style={styles.avatar} onPress={onPressAvatar}>
+          <UserAvatar
+            size={50}
+            handle={store.me.handle || ''}
+            displayName={store.me.displayName}
+          />
+        </TouchableOpacity>
+      ) : undefined}
       <View style={styles.textContainer}>
-        <Text style={styles.text}>What's up?</Text>
+        <Text style={styles.text}>{text}</Text>
       </View>
       <View style={styles.btn}>
-        <Text style={styles.btnText}>Post</Text>
+        <Text style={styles.btnText}>{btn}</Text>
       </View>
     </TouchableOpacity>
   )
@@ -40,6 +53,9 @@ const styles = StyleSheet.create({
     alignItems: 'center',
     backgroundColor: colors.white,
   },
+  noAviContainer: {
+    paddingVertical: 14,
+  },
   avatar: {
     width: 50,
   },