aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/components/common/GradientBorderButton.tsx2
-rw-r--r--src/components/common/TabsGradient.tsx2
-rw-r--r--src/components/profile/PublicProfile.tsx2
-rw-r--r--src/components/search/RecentSearches.tsx31
-rw-r--r--src/components/search/SearchBar.tsx37
-rw-r--r--src/components/search/SearchCategories.tsx68
-rw-r--r--src/components/search/SearchResultList.tsx85
-rw-r--r--src/components/search/SearchResults.tsx14
-rw-r--r--src/components/search/SearchResultsBackground.tsx69
-rw-r--r--src/screens/search/DiscoverUsers.tsx2
-rw-r--r--src/screens/search/SearchScreen.tsx180
11 files changed, 211 insertions, 281 deletions
diff --git a/src/components/common/GradientBorderButton.tsx b/src/components/common/GradientBorderButton.tsx
index 32ac5c52..a5dbde9d 100644
--- a/src/components/common/GradientBorderButton.tsx
+++ b/src/components/common/GradientBorderButton.tsx
@@ -42,7 +42,7 @@ const GradientBorderButton: React.FC<GradientBorderButtonProps> = ({
};
const styles = StyleSheet.create({
container: {
- marginVertical: 15,
+ marginVertical: 10,
},
gradientContainer: {
width: SCREEN_WIDTH / 2 - 40,
diff --git a/src/components/common/TabsGradient.tsx b/src/components/common/TabsGradient.tsx
index a95e8bc3..07c55042 100644
--- a/src/components/common/TabsGradient.tsx
+++ b/src/components/common/TabsGradient.tsx
@@ -14,7 +14,7 @@ const TabsGradient: React.FC = () => {
};
const styles = StyleSheet.create({
gradient: {
- position: 'absolute',
+ ...StyleSheet.absoluteFillObject,
top: (SCREEN_HEIGHT / 10) * 9,
height: SCREEN_HEIGHT / 10,
width: SCREEN_WIDTH,
diff --git a/src/components/profile/PublicProfile.tsx b/src/components/profile/PublicProfile.tsx
index 88e0ecd1..5f9b0b99 100644
--- a/src/components/profile/PublicProfile.tsx
+++ b/src/components/profile/PublicProfile.tsx
@@ -99,7 +99,7 @@ const PublicProfile: React.FC<ContentProps> = ({
scrollViewRef.current
) {
setScrollEnabled(false);
- scrollViewRef.current.getNode().scrollTo({y: 0});
+ scrollViewRef.current.scrollTo({y: 0});
navigation.navigate('MomentUploadPrompt', {
screenType,
momentCategory: momentCategories[0],
diff --git a/src/components/search/RecentSearches.tsx b/src/components/search/RecentSearches.tsx
index 84d35cac..6cea9338 100644
--- a/src/components/search/RecentSearches.tsx
+++ b/src/components/search/RecentSearches.tsx
@@ -6,6 +6,7 @@ import {
StyleSheet,
TouchableOpacityProps,
ScrollView,
+ Keyboard,
} from 'react-native';
import {
PreviewType,
@@ -15,7 +16,7 @@ import {
} from '../../types';
import {TAGG_LIGHT_BLUE} from '../../constants';
import SearchResults from './SearchResults';
-import {SCREEN_HEIGHT} from '../../utils';
+import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
interface RecentSearchesProps extends TouchableOpacityProps {
sectionTitle: PreviewType;
@@ -25,35 +26,25 @@ interface RecentSearchesProps extends TouchableOpacityProps {
}
const RecentSearches: React.FC<RecentSearchesProps> = (props) => {
- const {sectionTitle, recents, recentCategories, screenType} = props;
+ const {recents, recentCategories} = props;
return (
- <ScrollView
- style={styles.mainContainer}
- contentContainerStyle={styles.contentContainer}>
+ <>
<View style={styles.header}>
- <Text style={styles.title}>{sectionTitle}</Text>
+ <Text style={styles.title}>Recent</Text>
<TouchableOpacity {...props}>
<Text style={styles.clear}>Clear all</Text>
</TouchableOpacity>
</View>
- <SearchResults
- results={recents}
- categories={recentCategories}
- previewType={sectionTitle}
- screenType={screenType}
- />
- </ScrollView>
+ <ScrollView
+ onScrollBeginDrag={Keyboard.dismiss}
+ contentContainerStyle={{paddingBottom: useBottomTabBarHeight()}}>
+ <SearchResults results={recents} categories={recentCategories} />
+ </ScrollView>
+ </>
);
};
const styles = StyleSheet.create({
- mainContainer: {
- flex: 1,
- },
- contentContainer: {
- paddingBottom: SCREEN_HEIGHT * 0.1,
- flex: 1,
- },
header: {
paddingHorizontal: 25,
paddingVertical: 5,
diff --git a/src/components/search/SearchBar.tsx b/src/components/search/SearchBar.tsx
index 7b833406..d441b07b 100644
--- a/src/components/search/SearchBar.tsx
+++ b/src/components/search/SearchBar.tsx
@@ -9,20 +9,23 @@ import {
TextInputSubmitEditingEventData,
TouchableOpacity,
View,
+ ViewStyle,
+ LayoutChangeEvent,
} from 'react-native';
import {normalize} from 'react-native-elements';
-import Animated, {interpolate} from 'react-native-reanimated';
+import Animated, {useAnimatedStyle} from 'react-native-reanimated';
import Icon from 'react-native-vector-icons/Feather';
import {useSelector} from 'react-redux';
import {RootState} from '../../store/rootReducer';
-import {getSearchSuggestions, SCREEN_HEIGHT} from '../../utils';
+import {getSearchSuggestions} from '../../utils';
const AnimatedIcon = Animated.createAnimatedComponent(Icon);
interface SearchBarProps extends TextInputProps {
onCancel: () => void;
- top: Animated.Value<number>;
+ animationProgress: Animated.SharedValue<number>;
searching: boolean;
+ onLayout: (e: LayoutChangeEvent) => void;
}
const SearchBar: React.FC<SearchBarProps> = ({
onFocus,
@@ -31,7 +34,8 @@ const SearchBar: React.FC<SearchBarProps> = ({
value,
onCancel,
searching,
- top,
+ animationProgress,
+ onLayout,
}) => {
const handleSubmit = (
e: NativeSyntheticEvent<TextInputSubmitEditingEventData>,
@@ -107,23 +111,15 @@ const SearchBar: React.FC<SearchBarProps> = ({
}, [searching]);
/*
- * Animated nodes used in search bar activation animation.
+ * On-search marginRight style ("cancel" button slides and fades in).
*/
- // TODO: (Leon) use reanimated v2
- const marginRight = 0;
- // const marginRight: Animated.Node<number> = interpolate(top, {
- // inputRange: [-SCREEN_HEIGHT, 0],
- // outputRange: [0, 58],
- // });
- // TODO: (Leon) use reanimated v2
- const opacity = 0;
- // const opacity: Animated.Node<number> = interpolate(top, {
- // inputRange: [-SCREEN_HEIGHT, 0],
- // outputRange: [0, 1],
- // });
+ const animatedStyles = useAnimatedStyle<ViewStyle>(() => ({
+ marginRight: animationProgress.value * 58,
+ opacity: animationProgress.value,
+ }));
return (
- <View style={styles.container}>
+ <View style={styles.container} onLayout={onLayout}>
<Animated.View style={styles.inputContainer}>
<AnimatedIcon
name="search"
@@ -135,13 +131,13 @@ const SearchBar: React.FC<SearchBarProps> = ({
style={[styles.input]}
placeholderTextColor={'#828282'}
onSubmitEditing={handleSubmit}
- clearButtonMode="while-editing"
+ clearButtonMode="always"
autoCapitalize="none"
autoCorrect={false}
{...{placeholder, value, onChangeText, onFocus, onBlur}}
/>
</Animated.View>
- <Animated.View style={{marginRight, opacity}}>
+ <Animated.View style={animatedStyles}>
<TouchableOpacity style={styles.cancelButton} onPress={onCancel}>
<Text style={styles.cancelText}>Cancel</Text>
</TouchableOpacity>
@@ -155,6 +151,7 @@ const styles = StyleSheet.create({
height: 40,
paddingHorizontal: 20,
flexDirection: 'row',
+ zIndex: 2,
},
inputContainer: {
flexGrow: 1,
diff --git a/src/components/search/SearchCategories.tsx b/src/components/search/SearchCategories.tsx
index c747b34f..3d142981 100644
--- a/src/components/search/SearchCategories.tsx
+++ b/src/components/search/SearchCategories.tsx
@@ -3,29 +3,40 @@ import React, {useEffect, useState} from 'react';
import {StyleSheet, View} from 'react-native';
import {getSuggestedSearchBubbleSuggestions} from '../../services/ExploreService';
import {SearchCategoryType} from '../../types';
-import {SCREEN_WIDTH} from '../../utils';
import GradientBorderButton from '../common/GradientBorderButton';
+import {useSelector} from 'react-redux';
+import {RootState} from 'src/store/rootReducer';
interface SearchCategoriesProps {
darkStyle?: boolean;
- defaultButtons?: SearchCategoryType[];
+ useSuggestions: boolean;
}
const SearchCategories: React.FC<SearchCategoriesProps> = ({
darkStyle = false,
- defaultButtons,
+ useSuggestions,
}) => {
const navigation = useNavigation();
- const mtSearchCategory: (key: number) => SearchCategoryType = (key) => ({
+ const {
+ profile: {university = ''},
+ } = useSelector((state: RootState) => state.user);
+ const defaultButtons: SearchCategoryType[] = [21, 22, 23, 24].map(
+ (year, index) => ({
+ id: index * -1,
+ name: `${university.split(' ')[0]} '${year}`,
+ category: university,
+ }),
+ );
+ const createloadingCategory: (key: number) => SearchCategoryType = (key) => ({
id: key,
name: '...',
category: '...',
});
const [buttons, setButtons] = useState<SearchCategoryType[]>([
- mtSearchCategory(-1),
- mtSearchCategory(-2),
- mtSearchCategory(-3),
- mtSearchCategory(-4),
+ createloadingCategory(1),
+ createloadingCategory(2),
+ createloadingCategory(3),
+ createloadingCategory(4),
]);
useEffect(() => {
@@ -36,7 +47,7 @@ const SearchCategories: React.FC<SearchCategoriesProps> = ({
setButtons(localButtons);
}
};
- if (!defaultButtons) {
+ if (useSuggestions) {
loadButtons();
} else {
setButtons(defaultButtons);
@@ -45,33 +56,34 @@ const SearchCategories: React.FC<SearchCategoriesProps> = ({
return (
<View style={styles.container}>
- {buttons.map((searchCategory) => (
- <GradientBorderButton
- key={searchCategory.id}
- text={searchCategory.name}
- darkStyle={darkStyle}
- onPress={() => {
- if (searchCategory.name !== '...') {
- navigation.push('DiscoverUsers', {
- searchCategory,
- });
- }
- }}
- />
- ))}
+ <View style={styles.categoryContainer}>
+ {buttons.map((searchCategory, index) => (
+ <GradientBorderButton
+ key={index}
+ text={searchCategory.name}
+ darkStyle={darkStyle}
+ onPress={() => {
+ if (searchCategory.name !== '...') {
+ navigation.push('DiscoverUsers', {
+ searchCategory,
+ });
+ }
+ }}
+ />
+ ))}
+ </View>
</View>
);
};
const styles = StyleSheet.create({
container: {
- zIndex: 0,
- top: '3%',
- alignSelf: 'center',
+ paddingVertical: 20,
+ },
+ categoryContainer: {
flexDirection: 'row',
- width: SCREEN_WIDTH * 0.9,
- flexWrap: 'wrap',
justifyContent: 'space-evenly',
+ flexWrap: 'wrap',
},
});
export default SearchCategories;
diff --git a/src/components/search/SearchResultList.tsx b/src/components/search/SearchResultList.tsx
index 687b2285..a32760e1 100644
--- a/src/components/search/SearchResultList.tsx
+++ b/src/components/search/SearchResultList.tsx
@@ -1,15 +1,23 @@
import React, {useEffect, useState} from 'react';
-import {SectionList, StyleSheet, Text, View} from 'react-native';
+import {
+ SectionList,
+ StyleSheet,
+ Text,
+ View,
+ Keyboard,
+ SectionListData,
+} from 'react-native';
import {useSelector} from 'react-redux';
import {RootState} from '../../store/rootreducer';
import {NO_RESULTS_FOUND} from '../../constants/strings';
import {PreviewType, ScreenType} from '../../types';
-import {normalize, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
+import {normalize, SCREEN_WIDTH} from '../../utils';
import SearchResultsCell from './SearchResultCell';
+import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
interface SearchResultsProps {
- results: Array<any> | undefined;
- keyboardVisible: boolean;
+ // TODO: make sure results come in as same type, regardless of profile, category, badges
+ results: SectionListData<any>[];
previewType: PreviewType;
screenType: ScreenType;
}
@@ -21,11 +29,8 @@ const sectionHeader: React.FC<Boolean> = (showBorder: Boolean) => {
return null;
};
-const SearchResultList: React.FC<SearchResultsProps> = ({
- results,
- keyboardVisible,
-}) => {
- const [showEmptyView, setshowEmptyView] = useState(false);
+const SearchResultList: React.FC<SearchResultsProps> = ({results}) => {
+ const [showEmptyView, setshowEmptyView] = useState<boolean>(false);
const {user: loggedInUser} = useSelector((state: RootState) => state.user);
useEffect(() => {
@@ -38,57 +43,41 @@ const SearchResultList: React.FC<SearchResultsProps> = ({
}
}, [results]);
- return (
- <View style={styles.container}>
- {showEmptyView && (
- <View style={styles.noResultsTextContainer}>
- <Text style={styles.noResultsTextStyle}>{NO_RESULTS_FOUND}</Text>
- </View>
- )}
- {!showEmptyView && (
- <SectionList
- style={[
- {width: SCREEN_WIDTH},
- keyboardVisible ? styles.keyboardOpen : {},
- ]}
- contentContainerStyle={styles.sectionListContentContainer}
- sections={results}
- keyExtractor={(item, index) => item.id + index}
- renderItem={({section, item}) => {
- return (
- <SearchResultsCell
- profileData={item}
- loggedInUser={loggedInUser}
- />
- );
- }}
- renderSectionHeader={({section: {data}}) =>
- sectionHeader(data.length !== 0)
- }
- />
- )}
+ return showEmptyView ? (
+ <View style={styles.container} onTouchStart={Keyboard.dismiss}>
+ <Text style={styles.noResultsTextStyle}>{NO_RESULTS_FOUND}</Text>
</View>
+ ) : (
+ <SectionList
+ onScrollBeginDrag={Keyboard.dismiss}
+ contentContainerStyle={[{paddingBottom: useBottomTabBarHeight()}]}
+ sections={results}
+ keyExtractor={(item, index) => item.id + index}
+ renderItem={({item}) => {
+ return (
+ <SearchResultsCell profileData={item} loggedInUser={loggedInUser} />
+ );
+ }}
+ renderSectionHeader={({section: {data}}) =>
+ sectionHeader(data.length !== 0)
+ }
+ stickySectionHeadersEnabled={false}
+ />
);
};
const styles = StyleSheet.create({
container: {
- height: SCREEN_HEIGHT,
- paddingBottom: SCREEN_HEIGHT * 0.1,
- },
- sectionListContentContainer: {
- paddingBottom: SCREEN_HEIGHT * 0.15,
- width: SCREEN_WIDTH,
+ flex: 1,
+ marginTop: 30,
+ alignItems: 'center',
},
sectionHeaderStyle: {
width: '100%',
height: 0.5,
- marginBottom: normalize(24),
+ marginVertical: 5,
backgroundColor: '#C4C4C4',
},
- keyboardOpen: {
- marginBottom: SCREEN_HEIGHT * 0.35,
- },
noResultsTextContainer: {
justifyContent: 'center',
flexDirection: 'row',
diff --git a/src/components/search/SearchResults.tsx b/src/components/search/SearchResults.tsx
index ef518d8b..a73d0b40 100644
--- a/src/components/search/SearchResults.tsx
+++ b/src/components/search/SearchResults.tsx
@@ -1,18 +1,10 @@
import React from 'react';
-import {
- ProfilePreviewType,
- PreviewType,
- ScreenType,
- CategoryPreviewType,
-} from '../../types';
-import {View} from 'react-native';
+import {ProfilePreviewType, CategoryPreviewType} from '../../types';
import SearchResultsCell from './SearchResultCell';
import {useSelector} from 'react-redux';
import {RootState} from '../../store/rootReducer';
interface SearchResultsProps {
results: ProfilePreviewType[];
- previewType: PreviewType;
- screenType: ScreenType;
categories: CategoryPreviewType[];
}
const SearchResults: React.FC<SearchResultsProps> = ({results, categories}) => {
@@ -22,7 +14,7 @@ const SearchResults: React.FC<SearchResultsProps> = ({results, categories}) => {
*/
const {user: loggedInUser} = useSelector((state: RootState) => state.user);
return (
- <View>
+ <>
{categories
.slice(0)
.reverse()
@@ -43,7 +35,7 @@ const SearchResults: React.FC<SearchResultsProps> = ({results, categories}) => {
{...{loggedInUser}}
/>
))}
- </View>
+ </>
);
};
diff --git a/src/components/search/SearchResultsBackground.tsx b/src/components/search/SearchResultsBackground.tsx
index 3d7fab4e..e5236295 100644
--- a/src/components/search/SearchResultsBackground.tsx
+++ b/src/components/search/SearchResultsBackground.tsx
@@ -1,32 +1,55 @@
import React from 'react';
-import {StyleSheet} from 'react-native';
-import Animated, {interpolate} from 'react-native-reanimated';
-import {SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils';
+import {StyleSheet, ViewStyle} from 'react-native';
+import Animated, {
+ useAnimatedStyle,
+ useDerivedValue,
+ interpolate,
+ Extrapolate,
+} from 'react-native-reanimated';
+import {useSafeAreaInsets} from 'react-native-safe-area-context';
interface SearchResultsBackgroundProps {
- top: Animated.Value<number>;
+ animationProgress: Animated.SharedValue<number>;
+ searchBarHeight: number;
+ searching: boolean;
}
const SearchResultsBackground: React.FC<SearchResultsBackgroundProps> = ({
- top,
+ animationProgress,
+ searchBarHeight,
+ searching,
children,
}) => {
- // TODO: (Leon) use reanimated v2
- const opacityBackground = 0;
- // const opacityBackground: Animated.Node<number> = interpolate(top, {
- // inputRange: [-SCREEN_HEIGHT, 0],
- // outputRange: [0, 1],
- // });
- // TODO: (Leon) use reanimated v2
- const opacityContent = 0;
- // const opacityContent: Animated.Node<number> = interpolate(top, {
- // inputRange: [-SCREEN_HEIGHT / 40, 0],
- // outputRange: [0, 1],
- // });
+ const {top: topInset} = useSafeAreaInsets();
+ /*
+ * On-search container style (opacity fade-in).
+ */
+ const backgroundAnimatedStyles = useAnimatedStyle<ViewStyle>(() => ({
+ opacity: animationProgress.value,
+ }));
+ /*
+ * Derived animation value for contentAnimatedStyles.
+ */
+ const contentAnimationProgress = useDerivedValue<number>(() =>
+ interpolate(animationProgress.value, [0.9, 1], [0, 1], Extrapolate.CLAMP),
+ );
+ /*
+ * On-search content style (delayed opacity fade-in).
+ */
+ const contentAnimatedStyles = useAnimatedStyle<ViewStyle>(() => ({
+ opacity: contentAnimationProgress.value,
+ }));
return (
<Animated.View
- style={[styles.container, {opacity: opacityBackground, top}]}>
- <Animated.View
- style={[styles.contentContainer, {opacity: opacityContent}]}>
+ style={[
+ styles.container,
+ backgroundAnimatedStyles,
+ {
+ // absolute: inset + search screen paddingTop + searchBar + padding
+ paddingTop: topInset + 15 + searchBarHeight + 10,
+ },
+ ]}
+ pointerEvents={searching ? 'auto' : 'none'}>
+ <Animated.View style={[styles.contentContainer, contentAnimatedStyles]}>
{children}
</Animated.View>
</Animated.View>
@@ -34,15 +57,11 @@ const SearchResultsBackground: React.FC<SearchResultsBackgroundProps> = ({
};
const styles = StyleSheet.create({
container: {
- height: SCREEN_HEIGHT,
- width: SCREEN_WIDTH,
- position: 'absolute',
+ ...StyleSheet.absoluteFillObject,
backgroundColor: 'white',
},
contentContainer: {
flex: 1,
- paddingVertical: 10,
- paddingBottom: SCREEN_HEIGHT / 15,
},
});
export default SearchResultsBackground;
diff --git a/src/screens/search/DiscoverUsers.tsx b/src/screens/search/DiscoverUsers.tsx
index b87bfc37..f67585f2 100644
--- a/src/screens/search/DiscoverUsers.tsx
+++ b/src/screens/search/DiscoverUsers.tsx
@@ -126,7 +126,7 @@ const DiscoverUsers: React.FC<DiscoverUsersProps> = ({route}) => {
ListFooterComponent={() => (
<>
<Text style={styles.otherGroups}>Other Groups</Text>
- <SearchCategories darkStyle={true} />
+ <SearchCategories useSuggestions={true} darkStyle={true} />
</>
)}
/>
diff --git a/src/screens/search/SearchScreen.tsx b/src/screens/search/SearchScreen.tsx
index 4f0cabb4..f7e1c467 100644
--- a/src/screens/search/SearchScreen.tsx
+++ b/src/screens/search/SearchScreen.tsx
@@ -1,8 +1,19 @@
import AsyncStorage from '@react-native-community/async-storage';
import {useFocusEffect} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
-import {Keyboard, ScrollView, StatusBar, StyleSheet} from 'react-native';
-import Animated, {Easing, timing} from 'react-native-reanimated';
+import {
+ Keyboard,
+ StatusBar,
+ StyleSheet,
+ LayoutChangeEvent,
+ SectionListData,
+} from 'react-native';
+import {
+ useSharedValue,
+ withTiming,
+ Easing,
+ runOnJS,
+} from 'react-native-reanimated';
import {SafeAreaView} from 'react-native-safe-area-context';
import {useDispatch, useSelector} from 'react-redux';
import {
@@ -13,22 +24,14 @@ import {
SearchResultsBackground,
TabsGradient,
} from '../../components';
-import {SEARCH_ENDPOINT, TAGG_LIGHT_BLUE} from '../../constants';
+import {SEARCH_ENDPOINT} from '../../constants';
import {loadSearchResults} from '../../services';
import {resetScreenType} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
-import {
- CategoryPreviewType,
- ProfilePreviewType,
- ScreenType,
- SearchCategoryType,
-} from '../../types';
+import {CategoryPreviewType, ProfilePreviewType, ScreenType} from '../../types';
import {
getRecentlySearchedCategories,
getRecentlySearchedUsers,
- normalize,
- SCREEN_HEIGHT,
- SCREEN_WIDTH,
} from '../../utils';
/**
@@ -38,11 +41,8 @@ import {
const SearchScreen: React.FC = () => {
const {recentSearches} = useSelector((state: RootState) => state.taggUsers);
- const {
- profile: {university = ''},
- } = useSelector((state: RootState) => state.user);
const [query, setQuery] = useState<string>('');
- const [results, setResults] = useState<Array<any> | undefined>(undefined);
+ const [results, setResults] = useState<SectionListData<any>[] | undefined>();
const [recents, setRecents] = useState<Array<ProfilePreviewType>>(
recentSearches ?? [],
);
@@ -50,26 +50,12 @@ const SearchScreen: React.FC = () => {
CategoryPreviewType[]
>([]);
const [searching, setSearching] = useState(false);
- const top = Animated.useValue(-SCREEN_HEIGHT);
- const defaultButtons: SearchCategoryType[] = [21, 22, 23, 24].map((year) => ({
- id: -1,
- name: `${university.split(' ')[0]} '${year}`,
- category: university,
- }));
- const [keyboardVisible, setKeyboardVisible] = React.useState(
- 'keyboardVisible',
- );
- useEffect(() => {
- const showKeyboard = () => setKeyboardVisible('keyboardVisibleTrue');
- Keyboard.addListener('keyboardWillShow', showKeyboard);
- return () => Keyboard.removeListener('keyboardWillShow', showKeyboard);
- }, []);
+ /*
+ * Animated value
+ */
+ const animationProgress = useSharedValue<number>(0);
+ const [searchBarHeight, setSearchBarHeight] = useState<number>(0);
- useEffect(() => {
- const hideKeyboard = () => setKeyboardVisible('keyboardVisibleFalse');
- Keyboard.addListener('keyboardWillHide', hideKeyboard);
- return () => Keyboard.removeListener('keyboardWillHide', hideKeyboard);
- }, []);
const dispatch = useDispatch();
/*
@@ -122,12 +108,22 @@ const SearchScreen: React.FC = () => {
useEffect(() => {
if (searching) {
loadRecentlySearched().then(() => {
- timing(top, topInConfig).start();
+ animationProgress.value = withTiming(1, {
+ duration: 180,
+ easing: Easing.bezier(0.31, 0.14, 0.66, 0.82),
+ });
});
} else {
setQuery('');
handleBlur();
- timing(top, topOutConfig).start(() => setResults(undefined));
+ animationProgress.value = withTiming(
+ 0,
+ {duration: 180, easing: Easing.inOut(Easing.ease)},
+ () => {
+ 'worklet';
+ runOnJS(setResults)(undefined);
+ },
+ );
}
}, [searching]);
@@ -153,16 +149,6 @@ const SearchScreen: React.FC = () => {
}
};
- const topInConfig = {
- duration: 180,
- toValue: 0,
- easing: Easing.bezier(0.31, 0.14, 0.66, 0.82),
- };
- const topOutConfig = {
- duration: 180,
- toValue: -SCREEN_HEIGHT,
- easing: Easing.inOut(Easing.ease),
- };
const handleFocus = () => {
setSearching(true);
};
@@ -172,9 +158,12 @@ const SearchScreen: React.FC = () => {
const handleCancel = () => {
setSearching(false);
};
+ const onSearchBarLayout = (e: LayoutChangeEvent) => {
+ setSearchBarHeight(e.nativeEvent.layout.height);
+ };
return (
- <SafeAreaView style={styles.screenContainer}>
+ <SafeAreaView style={styles.container}>
<StatusBar barStyle="dark-content" />
<SearchBar
onCancel={handleCancel}
@@ -182,98 +171,39 @@ const SearchScreen: React.FC = () => {
onBlur={handleBlur}
onFocus={handleFocus}
value={query}
- {...{top, searching}}
+ onLayout={onSearchBarLayout}
+ {...{animationProgress, searching}}
/>
- <ScrollView
- scrollEnabled={!searching}
- keyboardShouldPersistTaps={'always'}
- stickyHeaderIndices={[4]}
- contentContainerStyle={styles.contentContainer}
- showsVerticalScrollIndicator={false}>
- <SearchCategories defaultButtons={defaultButtons} />
- <SearchResultsBackground {...{top}}>
- {results === undefined &&
- recents.length + recentCategories.length !== 0 ? (
+ <SearchCategories useSuggestions={false} />
+ <SearchResultsBackground
+ {...{searching, searchBarHeight, animationProgress}}>
+ {results === undefined ? (
+ recents.length + recentCategories.length > 0 && (
<RecentSearches
sectionTitle="Recent"
onPress={clearRecentlySearched}
screenType={ScreenType.Search}
{...{recents, recentCategories}}
/>
- ) : (
- <SearchResultList
- {...{results}}
- keyboardVisible={keyboardVisible === 'keyboardVisibleTrue'}
- previewType={'Search'}
- screenType={ScreenType.Search}
- />
- )}
- </SearchResultsBackground>
- </ScrollView>
+ )
+ ) : (
+ <SearchResultList
+ {...{results}}
+ previewType={'Search'}
+ screenType={ScreenType.Search}
+ />
+ )}
+ </SearchResultsBackground>
<TabsGradient />
</SafeAreaView>
);
};
const styles = StyleSheet.create({
- screenContainer: {
+ container: {
+ flex: 1,
paddingTop: 15,
backgroundColor: '#fff',
},
- contentContainer: {
- height: SCREEN_HEIGHT,
- paddingTop: '2%',
- paddingBottom: SCREEN_HEIGHT / 3,
- paddingHorizontal: '3%',
- },
- header: {
- marginVertical: 20,
- zIndex: 1,
- },
- recentsHeaderContainer: {
- flexDirection: 'row',
- },
- recentsHeader: {
- fontSize: 17,
- fontWeight: 'bold',
- flexGrow: 1,
- },
- clear: {
- fontSize: normalize(17),
- fontWeight: 'bold',
- color: TAGG_LIGHT_BLUE,
- },
- image: {
- width: SCREEN_WIDTH,
- height: SCREEN_WIDTH,
- },
- textContainer: {
- marginTop: '10%',
- },
- headerText: {
- color: '#fff',
- fontSize: normalize(32),
- fontWeight: '600',
- textAlign: 'center',
- marginBottom: '4%',
- marginHorizontal: '10%',
- },
- subtext: {
- color: '#fff',
- fontSize: normalize(16),
- fontWeight: '600',
- textAlign: 'center',
- marginHorizontal: '10%',
- },
- cancelButton: {
- position: 'absolute',
- height: '100%',
- justifyContent: 'center',
- paddingHorizontal: 5,
- },
- cancelText: {
- color: '#818181',
- fontWeight: '600',
- },
});
export default SearchScreen;