Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
83ad760
Bump flashlist to v2
zfurtak Aug 4, 2025
693ee87
Delete unused patch
zfurtak Aug 12, 2025
7a088ed
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 12, 2025
2044f62
Fix ts errors
zfurtak Aug 12, 2025
4ac00d8
Make patch for FlashList jest mock
zfurtak Aug 12, 2025
a7cc7c1
Add details to patch
zfurtak Aug 12, 2025
c56d753
Rename patch
zfurtak Aug 12, 2025
8879a65
Fix tests with ordering elements
zfurtak Aug 13, 2025
595031d
Update Mobile-Expensify
zfurtak Aug 13, 2025
7697461
Fix last test
zfurtak Aug 14, 2025
c848ff8
Add missing import
zfurtak Aug 14, 2025
6b6e6a4
Fix styling in emoji picker
zfurtak Aug 14, 2025
1ed5b5f
Adjust to review
zfurtak Aug 14, 2025
6e1f61e
Avoid unintended scrolling
zfurtak Aug 19, 2025
2da2b63
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 19, 2025
7853c2b
Avoid showing blank space when expense selected
zfurtak Aug 19, 2025
9cc2bb7
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 20, 2025
eaadc80
Fix fetching more reports bug
zfurtak Aug 21, 2025
d3a13a2
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 21, 2025
141b7fa
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 21, 2025
bc52d10
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 21, 2025
b01e6b8
Improve LHN performance
zfurtak Aug 22, 2025
ddb1827
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 22, 2025
6395f52
Move utility function back to SidebarOrderTest
zfurtak Aug 22, 2025
d17837d
Add comments to type
zfurtak Aug 25, 2025
4b66455
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 25, 2025
c66d59c
Fix lint
zfurtak Aug 25, 2025
fbd3085
Fix problem with loading next batch
zfurtak Aug 26, 2025
c62ab63
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 26, 2025
b628b69
Adjust fetchMoreResult function
zfurtak Aug 26, 2025
7fdaf1d
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 27, 2025
09bde05
Merge branch 'main' into @zfurtak/bump-flashlist-v2
zfurtak Aug 28, 2025
c502847
Change flashlist version to fixed 2.0.3
zfurtak Aug 28, 2025
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
24 changes: 4 additions & 20 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
"@react-navigation/stack": "7.3.3",
"@react-ng/bounds-observer": "^0.2.1",
"@rnmapbox/maps": "10.1.33",
"@shopify/flash-list": "1.8.2",
"@shopify/flash-list": "2.0.3",
"@ua/react-native-airship": "~24.4.0",
"awesome-phonenumber": "^5.4.0",
"babel-polyfill": "^6.26.0",
Expand Down Expand Up @@ -410,4 +410,4 @@
"node": "20.19.3",
"npm": "10.8.2"
}
}
}
45 changes: 0 additions & 45 deletions patches/recyclerlistview+4.2.3.patch

This file was deleted.

4 changes: 2 additions & 2 deletions src/components/DisplayNames/index.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import TextWithEmojiFragment from '@pages/home/report/comment/TextWithEmojiFragm
import type DisplayNamesProps from './types';

// As we don't have to show tooltips of the Native platform so we simply render the full display names list.
function DisplayNames({accessibilityLabel, fullTitle, textStyles = [], numberOfLines = 1, renderAdditionalText}: DisplayNamesProps) {
function DisplayNames({accessibilityLabel, fullTitle, textStyles = [], numberOfLines = 1, renderAdditionalText, testID}: DisplayNamesProps) {
const {translate} = useLocalize();
const titleContainsTextAndCustomEmoji = useMemo(() => containsCustomEmoji(fullTitle) && !containsOnlyCustomEmoji(fullTitle), [fullTitle]);
return (
<Text
accessibilityLabel={accessibilityLabel}
style={textStyles}
numberOfLines={numberOfLines}
testID={DisplayNames.displayName}
testID={`${DisplayNames.displayName}${testID !== undefined ? `-${testID}` : ''}`}
>
{titleContainsTextAndCustomEmoji ? (
<TextWithEmojiFragment
Expand Down
3 changes: 3 additions & 0 deletions src/components/DisplayNames/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ type DisplayNamesProps = {

/** Additional Text component to render after the displayNames */
renderAdditionalText?: () => React.ReactNode;

/** TestID indicating order */
testID?: number;
};

export default DisplayNamesProps;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import {FlashList} from '@shopify/flash-list';
import type {ListRenderItem} from '@shopify/flash-list';
import React, {useMemo} from 'react';
import type {FlashListRef, ListRenderItem} from '@shopify/flash-list';
import React from 'react';
import type {ForwardedRef} from 'react';
import {StyleSheet, View} from 'react-native';
import {View} from 'react-native';
import type {StyleProp, ViewStyle} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import CategoryShortcutBar from '@components/EmojiPicker/CategoryShortcutBar';
import EmojiSkinToneList from '@components/EmojiPicker/EmojiSkinToneList';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import type {EmojiPickerList, EmojiPickerListItem, HeaderIndices} from '@libs/EmojiUtils';
import CONST from '@src/CONST';

Expand Down Expand Up @@ -81,18 +79,9 @@ function ListEmptyComponent() {

function BaseEmojiPickerMenu(
{headerEmojis, scrollToHeader, isFiltered, listWrapperStyle = [], data, renderItem, stickyHeaderIndices = [], extraData = [], alwaysBounceVertical = false}: BaseEmojiPickerMenuProps,
ref: ForwardedRef<FlashList<EmojiPickerListItem>>,
ref: ForwardedRef<FlashListRef<EmojiPickerListItem>>,
) {
const styles = useThemeStyles();
const {windowWidth} = useWindowDimensions();
const {shouldUseNarrowLayout} = useResponsiveLayout();

// Estimated list size should be a whole integer to avoid floating point precision errors
// More info: https://github.com/Expensify/App/issues/34522
const listWidth = shouldUseNarrowLayout ? Math.floor(windowWidth) : CONST.EMOJI_PICKER_SIZE.WIDTH;

const flattenListWrapperStyle = useMemo(() => StyleSheet.flatten(listWrapperStyle), [listWrapperStyle]);

return (
<>
{!isFiltered && (
Expand All @@ -113,8 +102,6 @@ function BaseEmojiPickerMenu(
stickyHeaderIndices={stickyHeaderIndices}
ListEmptyComponent={ListEmptyComponent}
alwaysBounceVertical={alwaysBounceVertical}
estimatedItemSize={CONST.EMOJI_PICKER_ITEM_HEIGHT}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

estimatedListSize={{height: flattenListWrapperStyle.height as number, width: listWidth}}
contentContainerStyle={styles.ph4}
extraData={extraData}
getItemType={getItemType}
Expand Down
8 changes: 7 additions & 1 deletion src/components/EmojiPicker/EmojiPickerMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,13 @@ function EmojiPickerMenu({onEmojiSelected, activeEmoji}: EmojiPickerMenuProps, r

if ('header' in item && item.header) {
return (
<View style={[styles.emojiHeaderContainer, target === 'StickyHeader' ? styles.stickyHeaderEmoji(shouldUseNarrowLayout, windowWidth) : undefined]}>
<View
style={[
styles.emojiHeaderContainer,
styles.emojiHeaderContainerWidth(shouldUseNarrowLayout, windowWidth),
target === 'StickyHeader' ? styles.stickyHeaderEmoji : undefined,
]}
>
<Text style={styles.textLabelSupporting}>{translate(`emojiPicker.headers.${code}` as TranslationPaths)}</Text>
</View>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {FlashList} from '@shopify/flash-list';
import type {FlashListRef} from '@shopify/flash-list';
import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import emojis from '@assets/emojis';
import useKeyboardState from '@hooks/useKeyboardState';
Expand All @@ -12,7 +12,7 @@ import {getHeaderEmojis, getSpacersIndexes, mergeEmojisWithFrequentlyUsedEmojis,
import ONYXKEYS from '@src/ONYXKEYS';

const useEmojiPickerMenu = () => {
const emojiListRef = useRef<FlashList<EmojiPickerListItem>>(null);
const emojiListRef = useRef<FlashListRef<EmojiPickerListItem>>(null);
const [frequentlyUsedEmojis] = useOnyx(ONYXKEYS.FREQUENTLY_USED_EMOJIS, {canBeMissing: true});
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
const allEmojis = useMemo(() => mergeEmojisWithFrequentlyUsedEmojis(emojis, processFrequentlyUsedEmojis(frequentlyUsedEmojis)), [frequentlyUsedEmojis]);
Expand Down
15 changes: 7 additions & 8 deletions src/components/LHNOptionsList/LHNOptionsList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useIsFocused, useRoute} from '@react-navigation/native';
import type {FlashListProps} from '@shopify/flash-list';
import type {FlashListProps, FlashListRef} from '@shopify/flash-list';
import {FlashList} from '@shopify/flash-list';
import type {ReactElement} from 'react';
import React, {memo, useCallback, useContext, useEffect, useMemo, useRef} from 'react';
Expand All @@ -10,7 +10,6 @@ import * as Expensicons from '@components/Icon/Expensicons';
import LottieAnimations from '@components/LottieAnimations';
import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider';
import TextBlock from '@components/TextBlock';
import useLHNEstimatedListSize from '@hooks/useLHNEstimatedListSize';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
Expand Down Expand Up @@ -42,7 +41,7 @@ const keyExtractor = (item: Report) => `report_${item.reportID}`;
function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optionMode, shouldDisableFocusOptions = false, onFirstItemRendered = () => {}}: LHNOptionsListProps) {
const {saveScrollOffset, getScrollOffset, saveScrollIndex, getScrollIndex} = useContext(ScrollOffsetContext);
const {isOffline} = useNetwork();
const flashListRef = useRef<FlashList<Report>>(null);
const flashListRef = useRef<FlashListRef<Report>>(null);
const route = useRoute();
const isScreenFocused = useIsFocused();

Expand All @@ -63,7 +62,6 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
const theme = useTheme();
const styles = useThemeStyles();
const {translate, preferredLocale, localeCompare} = useLocalize();
const estimatedListSize = useLHNEstimatedListSize();
const isReportsSplitNavigatorLast = useRootNavigationState((state) => state?.routes?.at(-1)?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR);
const shouldShowEmptyLHN = data.length === 0;
const estimatedItemSize = optionMode === CONST.OPTION_MODE.COMPACT ? variables.optionRowHeightCompact : variables.optionRowHeight;
Expand Down Expand Up @@ -161,7 +159,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
* Function which renders a row in the list
*/
const renderItem = useCallback(
({item}: RenderItemProps): ReactElement => {
({item, index}: RenderItemProps): ReactElement => {
const reportID = item.reportID;
const itemParentReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${item.parentReportID}`];
const itemReportNameValuePairs = reportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportID}`];
Expand Down Expand Up @@ -248,6 +246,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
isReportsSplitNavigatorLast={isReportsSplitNavigatorLast}
isScreenFocused={isScreenFocused}
localeCompare={localeCompare}
testID={index}
isReportArchived={isReportArchived}
/>
);
Expand Down Expand Up @@ -398,14 +397,14 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
testID="lhn-options-list"
keyExtractor={keyExtractor}
renderItem={renderItem}
estimatedItemSize={estimatedItemSize}
overrideProps={{estimatedHeightSize: estimatedItemSize * CONST.LHN_VIEWPORT_ITEM_COUNT}}
extraData={extraData}
showsVerticalScrollIndicator={false}
onLayout={onLayout}
onScroll={onScroll}
estimatedListSize={estimatedListSize}
initialScrollIndex={isWebOrDesktop ? getScrollIndex(route) : undefined}
maintainVisibleContentPosition={{disabled: true}}
drawDistance={1000}
removeClippedSubviews
/>
)}
</View>
Expand Down
2 changes: 2 additions & 0 deletions src/components/LHNOptionsList/OptionRowLHN.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ function OptionRowLHN({
hasDraftComment,
shouldShowRBRorGBRTooltip,
isScreenFocused = false,
testID,
}: OptionRowLHNProps) {
const theme = useTheme();
const styles = useThemeStyles();
Expand Down Expand Up @@ -294,6 +295,7 @@ function OptionRowLHN({
isGroupChat(report) ||
isSystemChat(report)
}
testID={testID}
/>
{isChatUsedForOnboarding && <FreeTrial badgeStyles={[styles.mnh0, styles.pl2, styles.pr2, styles.ml1, styles.flexShrink1]} />}
{isStatusVisible && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import {CellContainer} from '@shopify/flash-list';
import type {CellContainerProps} from '@shopify/flash-list/dist/native/cell-container/CellContainer';
import type {ForwardedRef} from 'react';
import {forwardRef} from 'react';
import type {View} from 'react-native';
import type {ForwardedRef} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';

type OptionRowRendererComponentProps = {
/** The index position of this option row in the list */
index: number;

/** Callback function called when the component layout changes */
onLayout?: () => void;

/** Style prop for customizing the option row */
style?: StyleProp<ViewStyle>;
Comment thread
zfurtak marked this conversation as resolved.
};

function OptionRowRendererComponent(props: CellContainerProps, ref: ForwardedRef<View>) {
function OptionRowRendererComponent(props: OptionRowRendererComponentProps, ref: ForwardedRef<View>) {
return (
<CellContainer
<View
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={ref}
Expand Down
11 changes: 8 additions & 3 deletions src/components/LHNOptionsList/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type {ContentStyle} from '@shopify/flash-list';
import type {RefObject} from 'react';
import type {LayoutChangeEvent, StyleProp, TextStyle, View, ViewStyle} from 'react-native';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
Expand All @@ -16,7 +15,7 @@ type CustomLHNOptionsListProps = {
style?: StyleProp<ViewStyle>;

/** Extra styles for the section list container */
contentContainerStyles?: StyleProp<ContentStyle>;
contentContainerStyles?: StyleProp<ViewStyle>;

/** List of reports */
data: Report[];
Expand Down Expand Up @@ -129,6 +128,9 @@ type OptionRowLHNDataProps = {
/** Function to compare locale strings */
localeCompare: LocaleContextProps['localeCompare'];

/** TestID of the row, indicating order */
testID: number;

/** Whether the report is archived */
isReportArchived: boolean;
};
Expand Down Expand Up @@ -177,8 +179,11 @@ type OptionRowLHNProps = {

/** Whether the screen is focused */
isScreenFocused?: boolean;

/** The testID of the row */
testID: number;
};

type RenderItemProps = {item: Report};
type RenderItemProps = {item: Report; index: number};

export type {LHNOptionsListProps, OptionRowLHNDataProps, OptionRowLHNProps, RenderItemProps};
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@ function BaseSearchList({
ListFooterComponent,
onViewableItemsChanged,
onLayout,
estimatedItemSize,
overrideItemLayout,
estimatedListSize,
contentContainerStyle,
calculatedListHeight,
}: BaseSearchListProps) {
const renderItemWithoutKeyboardFocus = useCallback(
({item}: {item: SearchListItem; index: number}) => {
Expand All @@ -45,11 +41,8 @@ function BaseSearchList({
onLayout={onLayout}
removeClippedSubviews
drawDistance={1000}
estimatedItemSize={estimatedItemSize}
overrideItemLayout={overrideItemLayout}
estimatedListSize={estimatedListSize}
contentContainerStyle={contentContainerStyle}
overrideProps={{estimatedHeightSize: calculatedListHeight}}
maintainVisibleContentPosition={{disabled: true}}
/>
);
}
Expand Down
Loading
Loading