about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAnsh <anshnanda10@gmail.com>2023-07-28 08:29:37 -0700
committerGitHub <noreply@github.com>2023-07-28 10:29:37 -0500
commit38d78e16bffc9a25a45a4ad41caeef2c075daa26 (patch)
tree091bd4a86548899d64ad904c7f0fbf1fbb745778 /src
parent8e9b8b6b36bc5bb68737b783ae6accfd435fda8e (diff)
downloadvoidsky-38d78e16bffc9a25a45a4ad41caeef2c075daa26.tar.zst
Search custom feeds (#1031)
* paginate custom feeds

* basic search

* update `@atproto/api`

* use search from the API

* debounce search for 200ms
Diffstat (limited to 'src')
-rw-r--r--src/state/models/discovery/feeds.ts19
-rw-r--r--src/view/com/auth/create/Step1.tsx2
-rw-r--r--src/view/com/search/HeaderWithInput.tsx24
-rw-r--r--src/view/screens/DiscoverFeeds.tsx43
4 files changed, 75 insertions, 13 deletions
diff --git a/src/state/models/discovery/feeds.ts b/src/state/models/discovery/feeds.ts
index c484f7328..fa4054ff0 100644
--- a/src/state/models/discovery/feeds.ts
+++ b/src/state/models/discovery/feeds.ts
@@ -82,6 +82,21 @@ export class FeedsDiscoveryModel {
     this._xIdle()
   })
 
+  search = async (query: string) => {
+    this._xLoading(false)
+    try {
+      const results =
+        await this.rootStore.agent.app.bsky.unspecced.getPopularFeedGenerators({
+          limit: DEFAULT_LIMIT,
+          query: query,
+        })
+      this._replaceAll(results)
+    } catch (e: any) {
+      this._xIdle(e)
+    }
+    this._xIdle()
+  }
+
   clear() {
     this.isLoading = false
     this.isRefreshing = false
@@ -93,9 +108,9 @@ export class FeedsDiscoveryModel {
   // state transitions
   // =
 
-  _xLoading() {
+  _xLoading(isRefreshing = true) {
     this.isLoading = true
-    this.isRefreshing = true
+    this.isRefreshing = isRefreshing
     this.error = ''
   }
 
diff --git a/src/view/com/auth/create/Step1.tsx b/src/view/com/auth/create/Step1.tsx
index 5038c8819..5d3dec430 100644
--- a/src/view/com/auth/create/Step1.tsx
+++ b/src/view/com/auth/create/Step1.tsx
@@ -37,7 +37,7 @@ export const Step1 = observer(({model}: {model: CreateAccountModel}) => {
   }, [setIsDefaultSelected, model])
 
   const fetchServiceDescription = React.useMemo(
-    () => debounce(() => model.fetchServiceDescription(), 1e3),
+    () => debounce(() => model.fetchServiceDescription(), 1e3), // debouce for 1 second (1e3 = 1000ms)
     [model],
   )
 
diff --git a/src/view/com/search/HeaderWithInput.tsx b/src/view/com/search/HeaderWithInput.tsx
index 0d65d98fd..2ec079dde 100644
--- a/src/view/com/search/HeaderWithInput.tsx
+++ b/src/view/com/search/HeaderWithInput.tsx
@@ -21,6 +21,7 @@ interface Props {
   onPressClearQuery: () => void
   onPressCancelSearch: () => void
   onSubmitQuery: () => void
+  showMenu?: boolean
 }
 export function HeaderWithInput({
   isInputFocused,
@@ -30,6 +31,7 @@ export function HeaderWithInput({
   onPressClearQuery,
   onPressCancelSearch,
   onSubmitQuery,
+  showMenu = true,
 }: Props) {
   const store = useStores()
   const theme = useTheme()
@@ -49,16 +51,18 @@ export function HeaderWithInput({
 
   return (
     <View style={[pal.view, pal.border, styles.header]}>
-      <TouchableOpacity
-        testID="viewHeaderBackOrMenuBtn"
-        onPress={onPressMenu}
-        hitSlop={MENU_HITSLOP}
-        style={styles.headerMenuBtn}
-        accessibilityRole="button"
-        accessibilityLabel="Menu"
-        accessibilityHint="Access navigation links and settings">
-        <FontAwesomeIcon icon="bars" size={18} color={pal.colors.textLight} />
-      </TouchableOpacity>
+      {showMenu ? (
+        <TouchableOpacity
+          testID="viewHeaderBackOrMenuBtn"
+          onPress={onPressMenu}
+          hitSlop={MENU_HITSLOP}
+          style={styles.headerMenuBtn}
+          accessibilityRole="button"
+          accessibilityLabel="Menu"
+          accessibilityHint="Access navigation links and settings">
+          <FontAwesomeIcon icon="bars" size={18} color={pal.colors.textLight} />
+        </TouchableOpacity>
+      ) : null}
       <View
         style={[
           {backgroundColor: pal.colors.backgroundLight},
diff --git a/src/view/screens/DiscoverFeeds.tsx b/src/view/screens/DiscoverFeeds.tsx
index b6a6744db..e7b685ebc 100644
--- a/src/view/screens/DiscoverFeeds.tsx
+++ b/src/view/screens/DiscoverFeeds.tsx
@@ -14,6 +14,8 @@ import {isDesktopWeb} from 'platform/detection'
 import {usePalette} from 'lib/hooks/usePalette'
 import {s} from 'lib/styles'
 import {CustomFeedModel} from 'state/models/feeds/custom-feed'
+import {HeaderWithInput} from 'view/com/search/HeaderWithInput'
+import debounce from 'lodash.debounce'
 
 type Props = NativeStackScreenProps<CommonNavigatorParams, 'DiscoverFeeds'>
 export const DiscoverFeedsScreen = withAuthRequired(
@@ -22,6 +24,37 @@ export const DiscoverFeedsScreen = withAuthRequired(
     const pal = usePalette('default')
     const feeds = React.useMemo(() => new FeedsDiscoveryModel(store), [store])
 
+    // search stuff
+    const [isInputFocused, setIsInputFocused] = React.useState<boolean>(false)
+    const [query, setQuery] = React.useState<string>('')
+    const debouncedSearchFeeds = React.useMemo(
+      () => debounce(() => feeds.search(query), 200), // debouce for 200 ms
+      [feeds, query],
+    )
+    const onChangeQuery = React.useCallback(
+      (text: string) => {
+        setQuery(text)
+        if (text.length > 1) {
+          debouncedSearchFeeds()
+        } else {
+          feeds.refresh()
+        }
+      },
+      [debouncedSearchFeeds, feeds],
+    )
+    const onPressClearQuery = React.useCallback(() => {
+      setQuery('')
+      feeds.refresh()
+    }, [feeds])
+    const onPressCancelSearch = React.useCallback(() => {
+      setIsInputFocused(false)
+      setQuery('')
+      feeds.refresh()
+    }, [feeds])
+    const onSubmitQuery = React.useCallback(() => {
+      feeds.search(query)
+    }, [feeds, query])
+
     useFocusEffect(
       React.useCallback(() => {
         store.shell.setMinimalShellMode(false)
@@ -68,6 +101,16 @@ export const DiscoverFeedsScreen = withAuthRequired(
       <CenteredView style={[styles.container, pal.view]}>
         <View style={[isDesktopWeb && styles.containerDesktop, pal.border]}>
           <ViewHeader title="Discover Feeds" showOnDesktop />
+          <HeaderWithInput
+            isInputFocused={isInputFocused}
+            query={query}
+            setIsInputFocused={setIsInputFocused}
+            onChangeQuery={onChangeQuery}
+            onPressClearQuery={onPressClearQuery}
+            onPressCancelSearch={onPressCancelSearch}
+            onSubmitQuery={onSubmitQuery}
+            showMenu={false}
+          />
         </View>
         <FlatList
           style={[!isDesktopWeb && s.flex1]}