From 726ff6bb01d63c060c49bc1ea20fa1812e18723e Mon Sep 17 00:00:00 2001
From: Paul Frazee <pfrazee@gmail.com>
Date: Wed, 18 Jan 2023 13:21:23 -0600
Subject: Focus the text input on tap during the composer

---
 src/view/com/composer/ComposePost.tsx | 282 ++++++++++++++++++----------------
 1 file changed, 146 insertions(+), 136 deletions(-)

(limited to 'src/view/com/composer/ComposePost.tsx')

diff --git a/src/view/com/composer/ComposePost.tsx b/src/view/com/composer/ComposePost.tsx
index eaf927987..3cb31c536 100644
--- a/src/view/com/composer/ComposePost.tsx
+++ b/src/view/com/composer/ComposePost.tsx
@@ -9,6 +9,7 @@ import {
   StyleSheet,
   TextInput,
   TouchableOpacity,
+  TouchableWithoutFeedback,
   View,
 } from 'react-native'
 import LinearGradient from 'react-native-linear-gradient'
@@ -88,6 +89,9 @@ export const ComposePost = observer(function ComposePost({
     }
   }, [])
 
+  const onPressContainer = () => {
+    textInput.current?.focus()
+  }
   const onPressSelectPhotos = () => {
     if (isSelectingPhotos) {
       setIsSelectingPhotos(false)
@@ -183,156 +187,162 @@ export const ComposePost = observer(function ComposePost({
       testID="composePostView"
       behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
       style={[pal.view, styles.outer]}>
-      <SafeAreaView style={s.flex1}>
-        <View style={styles.topbar}>
-          <TouchableOpacity
-            testID="composerCancelButton"
-            onPress={onPressCancel}>
-            <Text style={[pal.link, s.f18]}>Cancel</Text>
-          </TouchableOpacity>
-          <View style={s.flex1} />
-          {isProcessing ? (
-            <View style={styles.postBtn}>
-              <ActivityIndicator />
-            </View>
-          ) : canPost ? (
+      <TouchableWithoutFeedback onPressIn={onPressContainer}>
+        <SafeAreaView style={s.flex1}>
+          <View style={styles.topbar}>
             <TouchableOpacity
-              testID="composerPublishButton"
-              onPress={onPressPublish}>
-              <LinearGradient
-                colors={[gradients.blueLight.start, gradients.blueLight.end]}
-                start={{x: 0, y: 0}}
-                end={{x: 1, y: 1}}
-                style={styles.postBtn}>
-                <Text style={[s.white, s.f16, s.bold]}>
-                  {replyTo ? 'Reply' : 'Post'}
-                </Text>
-              </LinearGradient>
+              testID="composerCancelButton"
+              onPress={onPressCancel}>
+              <Text style={[pal.link, s.f18]}>Cancel</Text>
             </TouchableOpacity>
-          ) : (
-            <View style={[styles.postBtn, pal.btn]}>
-              <Text style={[pal.textLight, s.f16, s.bold]}>Post</Text>
-            </View>
-          )}
-        </View>
-        {isProcessing ? (
-          <View style={[pal.btn, styles.processingLine]}>
-            <Text style={s.black}>{processingState}</Text>
+            <View style={s.flex1} />
+            {isProcessing ? (
+              <View style={styles.postBtn}>
+                <ActivityIndicator />
+              </View>
+            ) : canPost ? (
+              <TouchableOpacity
+                testID="composerPublishButton"
+                onPress={onPressPublish}>
+                <LinearGradient
+                  colors={[gradients.blueLight.start, gradients.blueLight.end]}
+                  start={{x: 0, y: 0}}
+                  end={{x: 1, y: 1}}
+                  style={styles.postBtn}>
+                  <Text style={[s.white, s.f16, s.bold]}>
+                    {replyTo ? 'Reply' : 'Post'}
+                  </Text>
+                </LinearGradient>
+              </TouchableOpacity>
+            ) : (
+              <View style={[styles.postBtn, pal.btn]}>
+                <Text style={[pal.textLight, s.f16, s.bold]}>Post</Text>
+              </View>
+            )}
           </View>
-        ) : undefined}
-        {error !== '' && (
-          <View style={styles.errorLine}>
-            <View style={styles.errorIcon}>
-              <FontAwesomeIcon
-                icon="exclamation"
-                style={{color: colors.red4}}
-                size={10}
-              />
+          {isProcessing ? (
+            <View style={[pal.btn, styles.processingLine]}>
+              <Text style={s.black}>{processingState}</Text>
             </View>
-            <Text style={[s.red4, s.flex1]}>{error}</Text>
-          </View>
-        )}
-        <ScrollView style={s.flex1}>
-          {replyTo ? (
-            <View style={[pal.border, styles.replyToLayout]}>
+          ) : undefined}
+          {error !== '' && (
+            <View style={styles.errorLine}>
+              <View style={styles.errorIcon}>
+                <FontAwesomeIcon
+                  icon="exclamation"
+                  style={{color: colors.red4}}
+                  size={10}
+                />
+              </View>
+              <Text style={[s.red4, s.flex1]}>{error}</Text>
+            </View>
+          )}
+          <ScrollView style={s.flex1}>
+            {replyTo ? (
+              <View style={[pal.border, styles.replyToLayout]}>
+                <UserAvatar
+                  handle={replyTo.author.handle}
+                  displayName={replyTo.author.displayName}
+                  avatar={replyTo.author.avatar}
+                  size={50}
+                />
+                <View style={styles.replyToPost}>
+                  <TextLink
+                    type="xl-medium"
+                    href={`/profile/${replyTo.author.handle}`}
+                    text={replyTo.author.displayName || replyTo.author.handle}
+                    style={[pal.text]}
+                  />
+                  <Text type="post-text" style={pal.text} numberOfLines={6}>
+                    {replyTo.text}
+                  </Text>
+                </View>
+              </View>
+            ) : undefined}
+            <View
+              style={[
+                pal.border,
+                styles.textInputLayout,
+                selectTextInputLayout,
+              ]}>
               <UserAvatar
-                handle={replyTo.author.handle}
-                displayName={replyTo.author.displayName}
-                avatar={replyTo.author.avatar}
+                handle={store.me.handle || ''}
+                displayName={store.me.displayName}
+                avatar={store.me.avatar}
                 size={50}
               />
-              <View style={styles.replyToPost}>
-                <TextLink
-                  type="xl-medium"
-                  href={`/profile/${replyTo.author.handle}`}
-                  text={replyTo.author.displayName || replyTo.author.handle}
-                  style={[pal.text]}
-                />
-                <Text type="post-text" style={pal.text} numberOfLines={6}>
-                  {replyTo.text}
-                </Text>
-              </View>
+              <TextInput
+                testID="composerTextInput"
+                ref={textInput}
+                multiline
+                scrollEnabled
+                onChangeText={(text: string) => onChangeText(text)}
+                placeholder={selectTextInputPlaceholder}
+                placeholderTextColor={pal.colors.textLight}
+                style={[pal.text, styles.textInput]}>
+                {textDecorated}
+              </TextInput>
             </View>
-          ) : undefined}
-          <View
-            style={[pal.border, styles.textInputLayout, selectTextInputLayout]}>
-            <UserAvatar
-              handle={store.me.handle || ''}
-              displayName={store.me.displayName}
-              avatar={store.me.avatar}
-              size={50}
-            />
-            <TextInput
-              testID="composerTextInput"
-              ref={textInput}
-              multiline
-              scrollEnabled
-              onChangeText={(text: string) => onChangeText(text)}
-              placeholder={selectTextInputPlaceholder}
-              placeholderTextColor={pal.colors.textLight}
-              style={[pal.text, styles.textInput]}>
-              {textDecorated}
-            </TextInput>
-          </View>
-          <SelectedPhoto
-            selectedPhotos={selectedPhotos}
-            onSelectPhotos={onSelectPhotos}
-          />
-        </ScrollView>
-        {isSelectingPhotos &&
-          localPhotos.photos != null &&
-          selectedPhotos.length < 4 && (
-            <PhotoCarouselPicker
+            <SelectedPhoto
               selectedPhotos={selectedPhotos}
               onSelectPhotos={onSelectPhotos}
-              localPhotos={localPhotos}
-            />
-          )}
-        <View style={[pal.border, styles.bottomBar]}>
-          <TouchableOpacity
-            testID="composerSelectPhotosButton"
-            onPress={onPressSelectPhotos}
-            style={[s.pl5]}
-            hitSlop={HITSLOP}>
-            <FontAwesomeIcon
-              icon={['far', 'image']}
-              style={selectedPhotos.length < 4 ? pal.link : pal.textLight}
-              size={24}
             />
-          </TouchableOpacity>
-          <View style={s.flex1} />
-          <Text style={[s.mr10, {color: progressColor}]}>
-            {MAX_TEXT_LENGTH - text.length}
-          </Text>
-          <View>
-            {text.length > DANGER_TEXT_LENGTH ? (
-              <ProgressPie
-                size={30}
-                borderWidth={4}
-                borderColor={progressColor}
-                color={progressColor}
-                progress={Math.min(
-                  (text.length - MAX_TEXT_LENGTH) / MAX_TEXT_LENGTH,
-                  1,
-                )}
-              />
-            ) : (
-              <ProgressCircle
-                size={30}
-                borderWidth={1}
-                borderColor={colors.gray2}
-                color={progressColor}
-                progress={text.length / MAX_TEXT_LENGTH}
+          </ScrollView>
+          {isSelectingPhotos &&
+            localPhotos.photos != null &&
+            selectedPhotos.length < 4 && (
+              <PhotoCarouselPicker
+                selectedPhotos={selectedPhotos}
+                onSelectPhotos={onSelectPhotos}
+                localPhotos={localPhotos}
               />
             )}
+          <View style={[pal.border, styles.bottomBar]}>
+            <TouchableOpacity
+              testID="composerSelectPhotosButton"
+              onPress={onPressSelectPhotos}
+              style={[s.pl5]}
+              hitSlop={HITSLOP}>
+              <FontAwesomeIcon
+                icon={['far', 'image']}
+                style={selectedPhotos.length < 4 ? pal.link : pal.textLight}
+                size={24}
+              />
+            </TouchableOpacity>
+            <View style={s.flex1} />
+            <Text style={[s.mr10, {color: progressColor}]}>
+              {MAX_TEXT_LENGTH - text.length}
+            </Text>
+            <View>
+              {text.length > DANGER_TEXT_LENGTH ? (
+                <ProgressPie
+                  size={30}
+                  borderWidth={4}
+                  borderColor={progressColor}
+                  color={progressColor}
+                  progress={Math.min(
+                    (text.length - MAX_TEXT_LENGTH) / MAX_TEXT_LENGTH,
+                    1,
+                  )}
+                />
+              ) : (
+                <ProgressCircle
+                  size={30}
+                  borderWidth={1}
+                  borderColor={colors.gray2}
+                  color={progressColor}
+                  progress={text.length / MAX_TEXT_LENGTH}
+                />
+              )}
+            </View>
           </View>
-        </View>
-        <Autocomplete
-          active={autocompleteView.isActive}
-          items={autocompleteView.suggestions}
-          onSelect={onSelectAutocompleteItem}
-        />
-      </SafeAreaView>
+          <Autocomplete
+            active={autocompleteView.isActive}
+            items={autocompleteView.suggestions}
+            onSelect={onSelectAutocompleteItem}
+          />
+        </SafeAreaView>
+      </TouchableWithoutFeedback>
     </KeyboardAvoidingView>
   )
 })
-- 
cgit 1.4.1

