From a0d6c8cd0886c3e6bae243360fa6f71455d3ba7c Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Mon, 28 Sep 2026 23:26:24 -0300 Subject: [PATCH 1/2] feat(rooms-list): render rooms list with Legend List --- ...etItemLayout.ts => useGetFixedItemSize.ts} | 14 +++-------- app/views/RoomsListView/index.tsx | 21 ++++++++--------- package.json | 1 + pnpm-lock.yaml | 23 +++++++++++++++++++ 4 files changed, 36 insertions(+), 23 deletions(-) rename app/views/RoomsListView/hooks/{useGetItemLayout.ts => useGetFixedItemSize.ts} (72%) diff --git a/app/views/RoomsListView/hooks/useGetItemLayout.ts b/app/views/RoomsListView/hooks/useGetFixedItemSize.ts similarity index 72% rename from app/views/RoomsListView/hooks/useGetItemLayout.ts rename to app/views/RoomsListView/hooks/useGetFixedItemSize.ts index 27c40ea897b..ef2542b0210 100644 --- a/app/views/RoomsListView/hooks/useGetItemLayout.ts +++ b/app/views/RoomsListView/hooks/useGetFixedItemSize.ts @@ -1,23 +1,15 @@ import { useCallback } from 'react'; import { shallowEqual } from 'react-redux'; +import { type IRoomItem } from '~/containers/RoomItem/interfaces'; import { DisplayMode } from '~/lib/constants/constantDisplayMode'; import { useAppSelector } from '~/lib/hooks/useAppSelector'; import { useResponsiveLayout } from '~/lib/hooks/useResponsiveLayout/useResponsiveLayout'; -export const useGetItemLayout = () => { +export const useGetFixedItemSize = () => { const { rowHeight, rowHeightCondensed } = useResponsiveLayout(); const { displayMode } = useAppSelector(state => state.sortPreferences, shallowEqual); const height = displayMode === DisplayMode.Condensed ? rowHeightCondensed : rowHeight; - const getItemLayout = useCallback( - (_: any, index: number) => ({ - length: height, - offset: height * index, - index - }), - [height] - ); - - return getItemLayout; + return useCallback((item: IRoomItem) => (item.separator ? undefined : height), [height]); }; diff --git a/app/views/RoomsListView/index.tsx b/app/views/RoomsListView/index.tsx index b7229c126cc..f411c3f05c8 100644 --- a/app/views/RoomsListView/index.tsx +++ b/app/views/RoomsListView/index.tsx @@ -1,6 +1,7 @@ import { useNavigation } from '@react-navigation/native'; import { memo, useContext, useEffect } from 'react'; -import { BackHandler, FlatList, RefreshControl } from 'react-native'; +import { LegendList } from '@legendapp/list/react-native'; +import { BackHandler, RefreshControl } from 'react-native'; import { useSafeAreaFrame, useSafeAreaInsets } from 'react-native-safe-area-context'; import { shallowEqual } from 'react-redux'; @@ -14,7 +15,7 @@ import i18n from '~/i18n'; import { MAX_SIDEBAR_WIDTH } from '~/lib/constants/tablet'; import { useAppSelector } from '~/lib/hooks/useAppSelector'; import { useMasterDetail } from '~/lib/hooks/useMasterDetail'; -import { getRoomAvatar, getRoomTitle, getUidDirectMessage, isIOS, isRead, isTablet } from '~/lib/methods/helpers'; +import { getRoomAvatar, getRoomTitle, getUidDirectMessage, isIOS, isRead } from '~/lib/methods/helpers'; import { goRoom } from '~/lib/methods/helpers/goRoom'; import { events, logEvent } from '~/lib/methods/helpers/log'; import { getUserSelector } from '~/selectors/login'; @@ -23,14 +24,12 @@ import Container from './components/Container'; import ListHeader from './components/ListHeader'; import SectionHeader from './components/SectionHeader'; import RoomsSearchProvider, { RoomsSearchContext } from './contexts/RoomsSearchProvider'; -import { useGetItemLayout } from './hooks/useGetItemLayout'; +import { useGetFixedItemSize } from './hooks/useGetFixedItemSize'; import { useHeader } from './hooks/useHeader'; import { useRefresh } from './hooks/useRefresh'; import { useSubscriptions } from './hooks/useSubscriptions'; import styles from './styles'; -const INITIAL_NUM_TO_RENDER = isTablet ? 20 : 12; - const RoomsListView = memo(function RoomsListView() { useHeader(); const { searching, searchEnabled, searchResults, stopSearch } = useContext(RoomsSearchContext); @@ -44,7 +43,7 @@ const RoomsListView = memo(function RoomsListView() { const navigation = useNavigation(); const { width } = useSafeAreaFrame(); const { bottom } = useSafeAreaInsets(); - const getItemLayout = useGetItemLayout(); + const getFixedItemSize = useGetFixedItemSize(); const { subscriptions, loading } = useSubscriptions(); const subscribedRoom = useAppSelector(state => state.room.subscribedRoom); const changingServer = useAppSelector(state => state.server.changingServer); @@ -126,21 +125,19 @@ const RoomsListView = memo(function RoomsListView() { } return ( - `${item.rid}-${searchEnabled}`} + getItemType={item => (item.separator ? 'separator' : 'room')} + getFixedItemSize={getFixedItemSize} style={[styles.list, { backgroundColor: colors.surfaceRoom }]} contentContainerStyle={{ paddingBottom: bottom }} renderItem={renderItem} ListHeaderComponent={ListHeader} - ListFooterComponent={searching ? () => : undefined} - getItemLayout={getItemLayout} + ListFooterComponent={searching ? : undefined} keyboardShouldPersistTaps='always' - initialNumToRender={INITIAL_NUM_TO_RENDER} refreshControl={} - windowSize={9} - onEndReachedThreshold={0.5} keyboardDismissMode={isIOS ? 'on-drag' : 'none'} /> ); diff --git a/package.json b/package.json index 96cf9e39a58..6855adc354e 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@bugsnag/react-native": "8.4.0", "@expo/vector-icons": "^15.0.3", "@hookform/resolvers": "^2.9.10", + "@legendapp/list": "3.4.0", "@lodev09/react-native-true-sheet": "~3.7.0", "@magrinj/expo-quick-look": "0.4.0", "@nozbe/watermelondb": "^0.28.1-0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ef049482418..3fc53628cba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@hookform/resolvers': specifier: ^2.9.10 version: 2.9.11(react-hook-form@7.34.2(react@19.2.3)) + '@legendapp/list': + specifier: 3.4.0 + version: 3.4.0(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native-community/cli@20.0.0(typescript@7.0.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7)(react@19.2.3))(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.18)(react@19.2.3))(react@19.2.3) '@lodev09/react-native-true-sheet': specifier: ~3.7.0 version: 3.7.3(4eac27da23d45fdf91d899c57069aba2) @@ -2125,6 +2128,18 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@legendapp/list@3.4.0': + resolution: {integrity: sha512-Tlx7Uf9pRP/JbrekuWdKf1+42C9MTfl1wGkP8Lvmg2E2T9rCWQphYOs8aOkcvgbAkJ2S+WR+RTXHS2+6U+nROw==} + peerDependencies: + react: '*' + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + '@lodev09/react-native-true-sheet@3.7.3': resolution: {integrity: sha512-vX/3F6lD3qH0GZfSVXL+JD/bjFPZtJa35Vyr9KCv94szOHXsjoEyCyi/52r5jw6jmq/KRALCqwidt9A15qq9gw==} peerDependencies: @@ -10321,6 +10336,14 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@legendapp/list@3.4.0(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native-community/cli@20.0.0(typescript@7.0.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7)(react@19.2.3))(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.18)(react@19.2.3))(react@19.2.3)': + dependencies: + react: 19.2.3 + use-sync-external-store: 1.6.0(react@19.2.3) + optionalDependencies: + react-dom: 19.2.3(react@19.2.3) + react-native: 0.86.3(@babel/core@7.29.7)(@react-native-community/cli@20.0.0(typescript@7.0.2))(@react-native/jest-preset@0.86.3(@babel/core@7.29.7)(react@19.2.3))(@react-native/metro-config@0.86.3(@babel/core@7.29.7))(@types/react@19.2.18)(react@19.2.3) + '@lodev09/react-native-true-sheet@3.7.3(4eac27da23d45fdf91d899c57069aba2)': dependencies: react: 19.2.3 From 04846faa72a2eb34b491678bdb1034bb1204750e Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Thu, 1 Oct 2026 06:30:36 -0300 Subject: [PATCH 2/2] fix(rooms-list): re-render room items when display preferences change --- app/views/RoomsListView/index.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/app/views/RoomsListView/index.tsx b/app/views/RoomsListView/index.tsx index f411c3f05c8..bcaf14bd900 100644 --- a/app/views/RoomsListView/index.tsx +++ b/app/views/RoomsListView/index.tsx @@ -124,10 +124,22 @@ const RoomsListView = memo(function RoomsListView() { return ; } + const rooms = searchEnabled ? searchResults : subscriptions; + return ( `${item.rid}-${searchEnabled}`} getItemType={item => (item.separator ? 'separator' : 'room')} getFixedItemSize={getFixedItemSize}