fix(mobile): removeClippedSubviews=false on grids — stop thumbnails vanishing on scroll
Android FlatList defaults removeClippedSubviews=true, which detaches off-viewport subviews; expo-image frequently fails to re-render them when they scroll back in → blank thumbnails (bug-report f181d382 2026-06-07, recurring). Disable on all heavy image grids: scene grids (Scenes/Site/Studio/Tag/Performer) + movie poster grids. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d4b89f16e3
commit
940d4872e3
6 changed files with 14 additions and 0 deletions
|
|
@ -133,6 +133,9 @@ export function MoviesScreen() {
|
||||||
data={items}
|
data={items}
|
||||||
numColumns={NUM_COLS}
|
numColumns={NUM_COLS}
|
||||||
keyExtractor={(m) => m.id}
|
keyExtractor={(m) => m.id}
|
||||||
|
// Android removeClippedSubviews=true blankuje plakaty po scrollu (expo-image
|
||||||
|
// nie re-renderuje odpiętych) — ten sam bug co "znikające miniaturki" scen.
|
||||||
|
removeClippedSubviews={false}
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<MoviePosterCard
|
<MoviePosterCard
|
||||||
movie={item}
|
movie={item}
|
||||||
|
|
|
||||||
|
|
@ -273,6 +273,10 @@ export function PerformerScenesScreen() {
|
||||||
data={sortedScenes}
|
data={sortedScenes}
|
||||||
keyExtractor={(s) => s.id}
|
keyExtractor={(s) => s.id}
|
||||||
numColumns={2}
|
numColumns={2}
|
||||||
|
// Android default removeClippedSubviews=true odpina miniaturki poza
|
||||||
|
// viewportem i expo-image często nie re-renderuje ich po powrocie →
|
||||||
|
// "miniaturki znikają przy scrollu" (bug-report f181d382 2026-06-07).
|
||||||
|
removeClippedSubviews={false}
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<SceneTile scene={item} seenSince={seenSince} secondLine="studio" />
|
<SceneTile scene={item} seenSince={seenSince} secondLine="studio" />
|
||||||
)}
|
)}
|
||||||
|
|
@ -347,6 +351,7 @@ export function PerformerScenesScreen() {
|
||||||
key="movies-list"
|
key="movies-list"
|
||||||
data={movies}
|
data={movies}
|
||||||
numColumns={MOVIE_COLS}
|
numColumns={MOVIE_COLS}
|
||||||
|
removeClippedSubviews={false}
|
||||||
keyExtractor={(m) => m.id}
|
keyExtractor={(m) => m.id}
|
||||||
renderItem={({ item }) => {
|
renderItem={({ item }) => {
|
||||||
// Defensive: jeśli backend kiedyś wyśle pojedynczy malformed movie,
|
// Defensive: jeśli backend kiedyś wyśle pojedynczy malformed movie,
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,9 @@ export function ScenesScreen() {
|
||||||
data={items}
|
data={items}
|
||||||
keyExtractor={(s) => s.id}
|
keyExtractor={(s) => s.id}
|
||||||
numColumns={2}
|
numColumns={2}
|
||||||
|
// Android removeClippedSubviews=true (default) blankuje miniaturki po scrollu —
|
||||||
|
// expo-image nie re-renderuje odpiętych subview. Bug-report "znikają miniaturki".
|
||||||
|
removeClippedSubviews={false}
|
||||||
renderItem={({ item }) => <SceneTile scene={item} />}
|
renderItem={({ item }) => <SceneTile scene={item} />}
|
||||||
columnWrapperStyle={styles.gridRow}
|
columnWrapperStyle={styles.gridRow}
|
||||||
ListHeaderComponent={!debouncedQ && activeCount === 0 ? <ContinueWatchingRail /> : null}
|
ListHeaderComponent={!debouncedQ && activeCount === 0 ? <ContinueWatchingRail /> : null}
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ export function SiteScenesScreen() {
|
||||||
data={items}
|
data={items}
|
||||||
keyExtractor={(s) => s.id}
|
keyExtractor={(s) => s.id}
|
||||||
numColumns={2}
|
numColumns={2}
|
||||||
|
removeClippedSubviews={false}
|
||||||
renderItem={({ item }) => <SceneTile scene={item} secondLine="studio" />}
|
renderItem={({ item }) => <SceneTile scene={item} secondLine="studio" />}
|
||||||
columnWrapperStyle={styles.gridRow}
|
columnWrapperStyle={styles.gridRow}
|
||||||
refreshing={isRefetching}
|
refreshing={isRefetching}
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ export function StudioScenesScreen() {
|
||||||
data={sortedItems}
|
data={sortedItems}
|
||||||
keyExtractor={(s) => s.id}
|
keyExtractor={(s) => s.id}
|
||||||
numColumns={2}
|
numColumns={2}
|
||||||
|
removeClippedSubviews={false}
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<SceneTile scene={item} seenSince={seenSince} secondLine="performers" />
|
<SceneTile scene={item} seenSince={seenSince} secondLine="performers" />
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ export function TagScenesScreen() {
|
||||||
data={data?.items ?? []}
|
data={data?.items ?? []}
|
||||||
keyExtractor={(s) => s.id}
|
keyExtractor={(s) => s.id}
|
||||||
numColumns={2}
|
numColumns={2}
|
||||||
|
removeClippedSubviews={false}
|
||||||
renderItem={({ item }) => <SceneTile scene={item} secondLine="studio" />}
|
renderItem={({ item }) => <SceneTile scene={item} secondLine="studio" />}
|
||||||
columnWrapperStyle={styles.gridRow}
|
columnWrapperStyle={styles.gridRow}
|
||||||
refreshing={isRefetching}
|
refreshing={isRefetching}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue