Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide mobile Search nav button + status tabs on scrollDown, but reveal on scrollUp #48258

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
0cdffe1
add animation logic
SzymczakJ Aug 29, 2024
ce6f1cc
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Aug 29, 2024
6ea15d8
prettify code
SzymczakJ Aug 30, 2024
ec1402b
adjust padding
SzymczakJ Sep 2, 2024
c2cb62e
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 2, 2024
e93ceca
make SearchPageHeader use SearchContext instead of accepting data param
SzymczakJ Sep 2, 2024
1e5ff51
move modals from Search/index to SearchPageHeader
SzymczakJ Sep 3, 2024
cd01f44
fix paddings
SzymczakJ Sep 3, 2024
ce7d213
fix EmptyState and Loading screen paddings
SzymczakJ Sep 3, 2024
709e93d
fix loading state bug
SzymczakJ Sep 3, 2024
317cc9e
fix PR comments
SzymczakJ Sep 3, 2024
8fd252b
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 4, 2024
8794f8c
fix typo in comment
SzymczakJ Sep 4, 2024
261df38
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 4, 2024
c59ff2f
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 6, 2024
c0866fa
fix PR comments
SzymczakJ Sep 6, 2024
ce2a6d3
remove getReportsFromSelectedTransactions from SearchUtils
SzymczakJ Sep 6, 2024
db5812c
fix
SzymczakJ Sep 6, 2024
b0bf4c0
fix lint
SzymczakJ Sep 6, 2024
217ebf3
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 9, 2024
552e596
merge main
SzymczakJ Sep 9, 2024
1218079
modify scroll speed
SzymczakJ Sep 9, 2024
c85e65f
fix animation
SzymczakJ Sep 10, 2024
a7cc0e4
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 11, 2024
28f7efe
clean up code
SzymczakJ Sep 11, 2024
b5ce7cd
fix pr comments
SzymczakJ Sep 11, 2024
060ea0d
fix pr comments
SzymczakJ Sep 11, 2024
888db7d
fix animation
SzymczakJ Sep 16, 2024
e222001
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 16, 2024
bb7fb4d
fix linter
SzymczakJ Sep 16, 2024
a51f7db
fix empty state not showing
SzymczakJ Sep 17, 2024
8319d34
clean up code
SzymczakJ Sep 18, 2024
9b7e621
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 18, 2024
487945d
clean up code
SzymczakJ Sep 18, 2024
7146a1d
fix styles
SzymczakJ Sep 18, 2024
91e44d4
fix PR comments
SzymczakJ Sep 20, 2024
0a672cf
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 20, 2024
786c2cb
fix PR comments
SzymczakJ Sep 20, 2024
3d556e4
fix modal not showing bug
SzymczakJ Sep 20, 2024
009d3d3
fix PR comments
SzymczakJ Sep 23, 2024
3fd8995
fix margin
SzymczakJ Sep 23, 2024
557625b
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 27, 2024
89f95be
fix PR comments
SzymczakJ Sep 27, 2024
c507ca1
fix styles
SzymczakJ Sep 27, 2024
ca27414
Merge branch 'main' into @szymczak/search-bar-hiding
SzymczakJ Sep 30, 2024
029f277
fix styles
SzymczakJ Sep 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5315,6 +5315,8 @@ const CONST = {
REPORT_ID: 'reportID',
KEYWORD: 'keyword',
},
TYPE_AND_STATUS_BAR_HEIGHT: 106,
SEARCH_HEADER_HEIGHT: 80,
},

REFERRER: {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Search/SearchStatusBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ function SearchStatusBar({type, status}: SearchStatusBarProps) {

return (
<ScrollView
style={[styles.flexRow, styles.mb5, styles.overflowScroll, styles.flexGrow0]}
style={[styles.flexRow, styles.mb2, styles.overflowScroll, styles.flexGrow0]}

This comment was marked as resolved.

horizontal
showsHorizontalScrollIndicator={false}
>
Expand Down
32 changes: 23 additions & 9 deletions src/components/Search/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {useNavigation} from '@react-navigation/native';
import type {StackNavigationProp} from '@react-navigation/stack';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import type {NativeScrollEvent, NativeSyntheticEvent} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import ConfirmModal from '@components/ConfirmModal';
Expand Down Expand Up @@ -37,6 +38,7 @@ import type {SearchColumnType, SearchQueryJSON, SearchStatus, SelectedTransactio
type SearchProps = {
queryJSON: SearchQueryJSON;
isCustomQuery: boolean;
onSearchListScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
};

const transactionItemMobileHeight = 100;
Expand Down Expand Up @@ -73,7 +75,7 @@ function prepareTransactionsList(item: TransactionListItemType, selectedTransact
return {...selectedTransactions, [item.keyForList]: {isSelected: true, canDelete: item.canDelete, canHold: item.canHold, canUnhold: item.canUnhold, action: item.action}};
}

function Search({queryJSON, isCustomQuery}: SearchProps) {
function Search({queryJSON, isCustomQuery, onSearchListScroll}: SearchProps) {
const {isOffline} = useNetwork();
const {translate} = useLocalize();
const styles = useThemeStyles();
Expand Down Expand Up @@ -199,6 +201,12 @@ function Search({queryJSON, isCustomQuery}: SearchProps) {
queryJSON={queryJSON}
hash={hash}
/>
{!isSmallScreenWidth && (
<SearchStatusBar
type={type}
status={status}
/>
)}
<SearchRowSkeleton shouldAnimate />
</>
);
Expand All @@ -224,10 +232,12 @@ function Search({queryJSON, isCustomQuery}: SearchProps) {
queryJSON={queryJSON}
hash={hash}
/>
<SearchStatusBar
type={type}
status={status}
/>
{!isSmallScreenWidth && (
<SearchStatusBar
type={type}
status={status}
/>
)}
<EmptySearchView type={type} />
</>
);
Expand Down Expand Up @@ -321,10 +331,12 @@ function Search({queryJSON, isCustomQuery}: SearchProps) {
setOfflineModalOpen={() => setOfflineModalVisible(true)}
setDownloadErrorModalOpen={() => setDownloadErrorModalVisible(true)}
/>
<SearchStatusBar
type={type}
status={status}
/>
{!isSmallScreenWidth && (
<SearchStatusBar
type={type}
status={status}
/>
)}
<SelectionListWithModal<ReportListItemType | TransactionListItemType>
sections={[{data: sortedSelectedData, isDisabled: false}]}
turnOnSelectionModeOnLongPress
Expand All @@ -344,6 +356,7 @@ function Search({queryJSON, isCustomQuery}: SearchProps) {
/>
)
}
onScroll={onSearchListScroll}
canSelectMultiple={canSelectMultiple}
customListHeaderHeight={searchHeaderHeight}
// To enhance the smoothness of scrolling and minimize the risk of encountering blank spaces during scrolling,
Expand Down Expand Up @@ -375,6 +388,7 @@ function Search({queryJSON, isCustomQuery}: SearchProps) {
/>
) : undefined
}
scrollEventThrottle={16}
/>
<ConfirmModal
isVisible={deleteExpensesConfirmModalVisible}
Expand Down
2 changes: 2 additions & 0 deletions src/components/SelectionList/BaseSelectionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ function BaseSelectionList<TItem extends ListItem>(
shouldUpdateFocusedIndex = false,
onLongPressRow,
shouldShowListEmptyContent = true,
scrollEventThrottle,
}: BaseSelectionListProps<TItem>,
ref: ForwardedRef<SelectionListHandle>,
) {
Expand Down Expand Up @@ -732,6 +733,7 @@ function BaseSelectionList<TItem extends ListItem>(
ListFooterComponent={listFooterContent ?? ShowMoreButtonInstance}
onEndReached={onEndReached}
onEndReachedThreshold={onEndReachedThreshold}
scrollEventThrottle={scrollEventThrottle}
/>
{children}
</>
Expand Down
5 changes: 4 additions & 1 deletion src/components/SelectionList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ function SelectionList<TItem extends ListItem>(props: BaseSelectionListProps<TIt
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={ref}
onScroll={() => {
onScroll={(event) => {
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
if (props.onScroll) {
props.onScroll(event);
}
// Only dismiss the keyboard whenever the user scrolls the screen
if (!isScreenTouched) {
return;
Expand Down
18 changes: 16 additions & 2 deletions src/components/SelectionList/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import type {MutableRefObject, ReactElement, ReactNode} from 'react';
import type {GestureResponderEvent, InputModeOptions, LayoutChangeEvent, SectionListData, StyleProp, TextInput, TextStyle, ViewStyle} from 'react-native';
import type {
GestureResponderEvent,
InputModeOptions,
LayoutChangeEvent,
NativeScrollEvent,
NativeSyntheticEvent,
SectionListData,
StyleProp,
TextInput,
TextStyle,
ViewStyle,
} from 'react-native';
import type {BrickRoad} from '@libs/WorkspacesSettingsUtils';
// eslint-disable-next-line no-restricted-imports
import type CursorStyles from '@styles/utils/cursor/types';
Expand Down Expand Up @@ -363,7 +374,7 @@ type BaseSelectionListProps<TItem extends ListItem> = Partial<ChildrenProps> & {
initiallyFocusedOptionKey?: string | null;

/** Callback to fire when the list is scrolled */
onScroll?: () => void;
onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;

/** Callback to fire when the list is scrolled and the user begins dragging */
onScrollBeginDrag?: () => void;
Expand Down Expand Up @@ -492,6 +503,9 @@ type BaseSelectionListProps<TItem extends ListItem> = Partial<ChildrenProps> & {

/** Whether to show the empty list content */
shouldShowListEmptyContent?: boolean;

/** Scroll event throttle for preventing onScroll callbacks to be fired too often */
scrollEventThrottle?: number;
} & TRightHandSideComponent<TItem>;

type SelectionListHandle = {
Expand Down
72 changes: 61 additions & 11 deletions src/pages/Search/SearchPageBottomTab.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import React, {useMemo} from 'react';
import {View} from 'react-native';
import type {NativeScrollEvent, NativeSyntheticEvent} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import Search from '@components/Search';
import {useSearchContext} from '@components/Search/SearchContext';
import SearchStatusBar from '@components/Search/SearchStatusBar';
import useActiveCentralPaneRoute from '@hooks/useActiveCentralPaneRoute';
import useLocalize from '@hooks/useLocalize';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode';
import Navigation from '@libs/Navigation/Navigation';
import type {AuthScreensParamList} from '@libs/Navigation/types';
import * as SearchUtils from '@libs/SearchUtils';
import TopBar from '@navigation/AppNavigator/createCustomBottomTabNavigator/TopBar';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
Expand All @@ -22,11 +28,44 @@ import SearchTypeMenu from './SearchTypeMenu';
function SearchPageBottomTab() {
const {translate} = useLocalize();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const {windowHeight} = useWindowDimensions();
const activeCentralPaneRoute = useActiveCentralPaneRoute();
const styles = useThemeStyles();
const {clearSelectedTransactions} = useSearchContext();
const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE);

const scrollOffset = useSharedValue(0);
const topBarOffset = useSharedValue(0);
const headerHeight = useSharedValue(CONST.SEARCH.SEARCH_HEADER_HEIGHT + CONST.SEARCH.TYPE_AND_STATUS_BAR_HEIGHT);
const animatedTopBarStyle = useAnimatedStyle(() => ({
transform: [{translateY: topBarOffset.value}],
zIndex: -1,
}));
const animatedHeaderStyle = useAnimatedStyle(() => ({
height: headerHeight.value,
}));

const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
const {contentOffset, layoutMeasurement, contentSize} = event.nativeEvent;
if (windowHeight + CONST.SEARCH.TYPE_AND_STATUS_BAR_HEIGHT > contentSize.height) {
return;
}

const currentOffset = contentOffset.y;
const isScrollingDown = currentOffset > scrollOffset.value;
if (isScrollingDown && contentOffset.y > 20) {
const distanceScrolled = currentOffset - scrollOffset.value;
// eslint-disable-next-line react-compiler/react-compiler
topBarOffset.value = Math.max(-CONST.SEARCH.TYPE_AND_STATUS_BAR_HEIGHT, topBarOffset.value - distanceScrolled);
headerHeight.value = Math.max(CONST.SEARCH.SEARCH_HEADER_HEIGHT, headerHeight.value - distanceScrolled);
} else if (!isScrollingDown && contentOffset.y + layoutMeasurement.height < contentSize.height - 10) {
topBarOffset.value = withTiming(0, {duration: 300});
SzymczakJ marked this conversation as resolved.
Show resolved Hide resolved
headerHeight.value = withTiming(CONST.SEARCH.SEARCH_HEADER_HEIGHT + CONST.SEARCH.TYPE_AND_STATUS_BAR_HEIGHT, {duration: 300});
}

scrollOffset.value = currentOffset;
};

const {queryJSON, policyID, isCustomQuery} = useMemo(() => {
if (activeCentralPaneRoute?.name !== SCREENS.SEARCH.CENTRAL_PANE) {
return {queryJSON: undefined, policyID: undefined, isCustomQuery: undefined};
Expand Down Expand Up @@ -56,17 +95,27 @@ function SearchPageBottomTab() {
shouldShowLink={false}
>
{!selectionMode?.isEnabled && queryJSON ? (
<>
<TopBar
activeWorkspaceID={policyID}
breadcrumbLabel={translate('common.search')}
shouldDisplaySearch={false}
/>
<SearchTypeMenu
isCustomQuery={isCustomQuery}
queryJSON={queryJSON}
/>
</>
<Animated.View style={animatedHeaderStyle}>
<View style={styles.appBG}>
<TopBar
activeWorkspaceID={policyID}
breadcrumbLabel={translate('common.search')}
shouldDisplaySearch={false}
/>
</View>
<Animated.View style={animatedTopBarStyle}>
<SearchTypeMenu
isCustomQuery={isCustomQuery}
queryJSON={queryJSON}
/>
{shouldUseNarrowLayout && (
<SearchStatusBar
type={queryJSON.type}
status={queryJSON.status}
/>
)}
</Animated.View>
</Animated.View>
) : (
<HeaderWithBackButton
title={translate('common.selectMultiple')}
Expand All @@ -80,6 +129,7 @@ function SearchPageBottomTab() {
<Search
queryJSON={queryJSON}
isCustomQuery={isCustomQuery}
onSearchListScroll={handleScroll}
/>
)}
</FullPageNotFoundView>
Expand Down
Loading