From 2b98714548d585ff14dd09252233144f48b5f4b7 Mon Sep 17 00:00:00 2001
From: Paul Frazee <pfrazee@gmail.com>
Date: Thu, 17 Nov 2022 14:35:12 -0600
Subject: Add live search to autocomplete and only highlight known handles

---
 src/view/com/composer/ComposePost.tsx | 56 ++++++++++++++---------------------
 1 file changed, 22 insertions(+), 34 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 0a7fadce1..cdd232fb6 100644
--- a/src/view/com/composer/ComposePost.tsx
+++ b/src/view/com/composer/ComposePost.tsx
@@ -1,4 +1,5 @@
 import React, {useEffect, useMemo, useState} from 'react'
+import {observer} from 'mobx-react-lite'
 import {
   ActivityIndicator,
   KeyboardAvoidingView,
@@ -11,7 +12,7 @@ import {
 } from 'react-native'
 import LinearGradient from 'react-native-linear-gradient'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import * as GetFollows from '../../../third-party/api/src/client/types/app/bsky/graph/getFollows'
+import {UserAutocompleteViewModel} from '../../../state/models/user-autocomplete-view'
 import {Autocomplete} from './Autocomplete'
 import Toast from '../util/Toast'
 import ProgressCircle from '../util/ProgressCircle'
@@ -24,7 +25,7 @@ const MAX_TEXT_LENGTH = 256
 const WARNING_TEXT_LENGTH = 200
 const DANGER_TEXT_LENGTH = MAX_TEXT_LENGTH
 
-export function ComposePost({
+export const ComposePost = observer(function ComposePost({
   replyTo,
   onPost,
   onClose,
@@ -37,40 +38,24 @@ export function ComposePost({
   const [isProcessing, setIsProcessing] = useState(false)
   const [error, setError] = useState('')
   const [text, setText] = useState('')
-  const [followedUsers, setFollowedUsers] = useState<
-    undefined | GetFollows.OutputSchema['follows']
-  >(undefined)
-  const [autocompleteOptions, setAutocompleteOptions] = useState<string[]>([])
+  const autocompleteView = useMemo<UserAutocompleteViewModel>(
+    () => new UserAutocompleteViewModel(store),
+    [],
+  )
 
   useEffect(() => {
-    let aborted = false
-    store.api.app.bsky.graph
-      .getFollows({
-        user: store.me.did || '',
-      })
-      .then(res => {
-        if (aborted) return
-        setFollowedUsers(res.data.follows)
-      })
-    return () => {
-      aborted = true
-    }
+    autocompleteView.setup()
   })
 
   const onChangeText = (newText: string) => {
     setText(newText)
 
     const prefix = extractTextAutocompletePrefix(newText)
-    if (typeof prefix === 'string' && followedUsers) {
-      setAutocompleteOptions(
-        [prefix].concat(
-          followedUsers
-            .filter(user => user.handle.startsWith(prefix))
-            .map(user => user.handle),
-        ),
-      )
-    } else if (autocompleteOptions) {
-      setAutocompleteOptions([])
+    if (typeof prefix === 'string') {
+      autocompleteView.setActive(true)
+      autocompleteView.setPrefix(prefix)
+    } else {
+      autocompleteView.setActive(false)
     }
   }
   const onPressCancel = () => {
@@ -90,7 +75,7 @@ export function ComposePost({
     }
     setIsProcessing(true)
     try {
-      await apilib.post(store, text, replyTo)
+      await apilib.post(store, text, replyTo, autocompleteView.knownHandles)
     } catch (e: any) {
       console.error(`Failed to create post: ${e.toString()}`)
       setError(
@@ -111,7 +96,7 @@ export function ComposePost({
   }
   const onSelectAutocompleteItem = (item: string) => {
     setText(replaceTextAutocompletePrefix(text, item))
-    setAutocompleteOptions([])
+    autocompleteView.setActive(false)
   }
 
   const canPost = text.length <= MAX_TEXT_LENGTH
@@ -124,7 +109,10 @@ export function ComposePost({
 
   const textDecorated = useMemo(() => {
     return (text || '').split(/(\s)/g).map((item, i) => {
-      if (/^@[a-zA-Z0-9\.-]+$/g.test(item)) {
+      if (
+        /^@[a-zA-Z0-9\.-]+$/g.test(item) &&
+        autocompleteView.knownHandles.has(item.slice(1))
+      ) {
         return (
           <Text key={i} style={{color: colors.blue3}}>
             {item}
@@ -198,14 +186,14 @@ export function ComposePost({
           </View>
         </View>
         <Autocomplete
-          active={autocompleteOptions.length > 0}
-          items={autocompleteOptions}
+          active={autocompleteView.isActive}
+          items={autocompleteView.suggestions}
           onSelect={onSelectAutocompleteItem}
         />
       </SafeAreaView>
     </KeyboardAvoidingView>
   )
-}
+})
 
 const atPrefixRegex = /@([\S]*)$/i
 function extractTextAutocompletePrefix(text: string) {
-- 
cgit 1.4.1

