Skip to content

Commit 41a26ff

Browse files
committed
perf(filen-mobile): skip thumbnail generation during FlashList measurement
Use FlashList's RenderTarget to gate thumbnail generation — items rendered for measurement (target !== "Cell") skip generation entirely. Combined with drawDistance={0}, this prevents wasted work for items that aren't actually visible on screen.
1 parent f90462a commit 41a26ff

File tree

4 files changed

+36
-35
lines changed

4 files changed

+36
-35
lines changed

packages/filen-mobile/src/components/drive/item/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ const Item = memo(({ info, drivePath }: { info: ListRenderItemInfo<DriveItem>; d
309309
)}
310310
<Thumbnail
311311
item={info.item}
312+
target={info.target}
312313
size={{
313314
icon: 38,
314315
thumbnail: 38

packages/filen-mobile/src/components/drive/item/thumbnail.tsx

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { run, runEffect } from "@filen/utils"
66
import Image from "@/components/ui/image"
77
import { FileIcon, DirectoryIcon } from "@/components/itemIcons"
88
import { DirColor } from "@filen/sdk-rs"
9-
import { useRecyclingState } from "@shopify/flash-list"
9+
import { type RenderTarget, useRecyclingState } from "@shopify/flash-list"
1010
import { AppState } from "react-native"
1111
import useHttpStore from "@/stores/useHttp.store"
1212
import { useFocusEffect } from "expo-router"
@@ -38,12 +38,14 @@ const FileThumbnailWithGenerate = memo(
3838
item,
3939
size,
4040
className,
41-
contentFit
41+
contentFit,
42+
target = "Cell"
4243
}: {
4344
item: DriveItemFileExtracted
4445
size: ThumbnailSize
4546
className?: string
4647
contentFit?: React.ComponentProps<typeof Image>["contentFit"]
48+
target?: RenderTarget
4749
}) => {
4850
const abortControllerRef = useRef<AbortController | null>(null)
4951
const errorRetryCountRef = useRef<number>(0)
@@ -69,13 +71,11 @@ const FileThumbnailWithGenerate = memo(
6971
}
7072
)
7173

72-
const localPathRef = useRef(localPath)
73-
74-
useEffect(() => {
75-
localPathRef.current = localPath
76-
}, [localPath])
77-
7874
const generate = useCallback(async () => {
75+
if (target !== "Cell" || localPath || !thumbnails.canGenerate(item) || AppState.currentState !== "active") {
76+
return
77+
}
78+
7979
const result = await run(async defer => {
8080
if (isGeneratingRef.current) {
8181
return
@@ -87,7 +87,7 @@ const FileThumbnailWithGenerate = memo(
8787
isGeneratingRef.current = false
8888
})
8989

90-
if (localPathRef.current || !thumbnails.canGenerate(item) || AppState.currentState !== "active") {
90+
if (target !== "Cell" || localPath || !thumbnails.canGenerate(item) || AppState.currentState !== "active") {
9191
return
9292
}
9393

@@ -137,13 +137,7 @@ const FileThumbnailWithGenerate = memo(
137137

138138
return
139139
}
140-
}, [item, setLocalPath])
141-
142-
const generateRef = useRef(generate)
143-
144-
useEffect(() => {
145-
generateRef.current = generate
146-
}, [generate])
140+
}, [item, setLocalPath, target, localPath])
147141

148142
const onFailure = () => {
149143
cache.availableThumbnails.delete(item.data.uuid)
@@ -158,20 +152,29 @@ const FileThumbnailWithGenerate = memo(
158152

159153
thumbnails.remove(item)
160154

161-
localPathRef.current = null
162-
163155
setLocalPath(null)
164156

165-
generateRef.current?.()
157+
generate()
158+
}
159+
160+
const source = !localPath
161+
? null
162+
: {
163+
uri: localPath
164+
}
165+
166+
const imageStyle = {
167+
width: size.thumbnail,
168+
height: size.thumbnail
166169
}
167170

168171
useEffect(() => {
169172
errorRetryCountRef.current = 0
170173

171-
if (!localPathRef.current) {
174+
if (!localPath) {
172175
generate()
173176
}
174-
}, [generate])
177+
}, [target, generate, localPath])
175178

176179
useEffect(() => {
177180
const { cleanup } = runEffect(defer => {
@@ -234,17 +237,6 @@ const FileThumbnailWithGenerate = memo(
234237
}, [])
235238
)
236239

237-
const source = !localPath
238-
? null
239-
: {
240-
uri: localPath
241-
}
242-
243-
const imageStyle = {
244-
width: size.thumbnail,
245-
height: size.thumbnail
246-
}
247-
248240
if (!localPath || !source) {
249241
return (
250242
<FileIcon
@@ -275,12 +267,14 @@ const FileThumbnail = memo(
275267
item,
276268
size,
277269
className,
278-
contentFit
270+
contentFit,
271+
target
279272
}: {
280273
item: DriveItemFileExtracted
281274
size: ThumbnailSize
282275
className?: string
283276
contentFit?: React.ComponentProps<typeof Image>["contentFit"]
277+
target?: RenderTarget
284278
}) => {
285279
const [localPath] = useRecyclingState<string | null>(() => {
286280
const available = cache.availableThumbnails.get(item.data.uuid)
@@ -325,6 +319,7 @@ const FileThumbnail = memo(
325319
size={size}
326320
className={className}
327321
contentFit={contentFit}
322+
target={target}
328323
/>
329324
)
330325
}
@@ -335,12 +330,14 @@ const Thumbnail = memo(
335330
item,
336331
size,
337332
className,
338-
contentFit
333+
contentFit,
334+
target
339335
}: {
340336
item: DriveItem
341337
size: ThumbnailSize
342338
className?: string
343339
contentFit?: React.ComponentProps<typeof Image>["contentFit"]
340+
target?: RenderTarget
344341
}) => {
345342
if (item.type === "file" || item.type === "sharedFile" || item.type === "sharedRootFile") {
346343
return (
@@ -349,6 +346,7 @@ const Thumbnail = memo(
349346
size={size}
350347
className={className}
351348
contentFit={contentFit}
349+
target={target}
352350
/>
353351
)
354352
}

packages/filen-mobile/src/routes/tabs/photos/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ const Photo = memo(
107107
)}
108108
<Thumbnail
109109
item={info.item}
110+
target={info.target}
110111
contentFit="cover"
111112
size={thumbnailSize}
112113
/>

packages/filen-mobile/src/routes/transfers/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { DirectoryIcon, FileIcon } from "@/components/itemIcons"
1818
import { DirColor } from "@filen/sdk-rs"
1919
import transfersLib from "@/lib/transfers"
2020

21-
const Transfer = memo(({ info: { item: transfer } }: { info: ListRenderItemInfo<TTransfer> }) => {
21+
const Transfer = memo(({ info: { item: transfer, target } }: { info: ListRenderItemInfo<TTransfer> }) => {
2222
const textForeground = useResolveClassNames("text-foreground")
2323

2424
return (
@@ -44,6 +44,7 @@ const Transfer = memo(({ info: { item: transfer } }: { info: ListRenderItemInfo<
4444
) : (
4545
<Thumbnail
4646
item={transfer.item}
47+
target={target}
4748
size={{
4849
icon: 32,
4950
thumbnail: 32

0 commit comments

Comments
 (0)