diff options
author | Ansh <anshnanda10@gmail.com> | 2023-07-28 08:29:37 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-28 10:29:37 -0500 |
commit | 38d78e16bffc9a25a45a4ad41caeef2c075daa26 (patch) | |
tree | 091bd4a86548899d64ad904c7f0fbf1fbb745778 | |
parent | 8e9b8b6b36bc5bb68737b783ae6accfd435fda8e (diff) | |
download | voidsky-38d78e16bffc9a25a45a4ad41caeef2c075daa26.tar.zst |
Search custom feeds (#1031)
* paginate custom feeds * basic search * update `@atproto/api` * use search from the API * debounce search for 200ms
-rw-r--r-- | .eslintrc.js | 1 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/state/models/discovery/feeds.ts | 19 | ||||
-rw-r--r-- | src/view/com/auth/create/Step1.tsx | 2 | ||||
-rw-r--r-- | src/view/com/search/HeaderWithInput.tsx | 24 | ||||
-rw-r--r-- | src/view/screens/DiscoverFeeds.tsx | 43 | ||||
-rw-r--r-- | yarn.lock | 8 |
7 files changed, 81 insertions, 18 deletions
diff --git a/.eslintrc.js b/.eslintrc.js index 8a733a20c..3de954e43 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,6 +15,7 @@ module.exports = { 'coverage', '*.lock', '.husky', + 'patches', ], overrides: [ { diff --git a/package.json b/package.json index 3d52305ae..4bb540878 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "e2e:run": "detox test --configuration ios.sim.debug --take-screenshots all" }, "dependencies": { - "@atproto/api": "^0.4.2", + "@atproto/api": "^0.4.3", "@bam.tech/react-native-image-resizer": "^3.0.4", "@braintree/sanitize-url": "^6.0.2", "@expo/html-elements": "^0.4.2", 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]} diff --git a/yarn.lock b/yarn.lock index 4217fb1be..fe1296aca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -40,10 +40,10 @@ tlds "^1.234.0" typed-emitter "^2.1.0" -"@atproto/api@^0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.4.2.tgz#7790eb049f72437e7454c8ecc29a5ef4201c1ade" - integrity sha512-bwaT+kIJp6wpzlHc1Rus3yi29GKlwvYp4wOWAFmcyYT4qH2ZlE6NfElgi6QwdQD285EhiIKYTv7CAMRp/QO7DQ== +"@atproto/api@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.4.3.tgz#d7e478bf7009df2adaf1ac6051eb3e3fea185c90" + integrity sha512-8LdREwmoA58YQDrLS0rohd7cHokhoiXfyYEeNtNlkdO0w/2QpkUCQ1PgPBP2kIRM9PhOEkKp7W3Sn8Te9Qq8jg== dependencies: "@atproto/common-web" "*" "@atproto/uri" "*" |