fix(performer): tag chips → in-place horizontal filter selector

Follow-up to 1a4bf258 feedback (a627637b + 0264a3ff): the flexWrap chip list ate
too much vertical space and tapping navigated away to TagScenes. Rework: single-row
horizontal scroll of toggle-chips that filter the performer's scenes IN-PLACE
(performer_ids + tags in one listScenes query, no navigation). Selected chip is
highlighted with a ✕ affordance; tap again clears. One line tall instead of N rows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jtrzupek 2026-06-09 09:25:02 +02:00
parent 576a424615
commit 7f36865b5a

View file

@ -13,6 +13,7 @@ import {
Alert,
FlatList,
Pressable,
ScrollView,
StyleSheet,
Text,
View,
@ -135,11 +136,16 @@ export function PerformerScenesScreen() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [navigation, name, isFavorite, addMutation.isPending, removeMutation.isPending]);
// Filtr tagu IN-PLACE (bug-report 0264a3ff: wybór tagu ma filtrować sceny tej
// aktorki w tym widoku, nie nawigować do osobnego ekranu). null = bez filtra.
const [selectedTag, setSelectedTag] = React.useState<{ slug: string; name: string } | null>(null);
const scenesQuery = useQuery({
queryKey: ['performer-scenes', id],
queryKey: ['performer-scenes', id, selectedTag?.slug ?? null],
queryFn: () =>
client.listScenes({
performer_ids: [id],
tags: selectedTag ? [selectedTag.slug] : undefined,
sort: 'release_date',
per_page: 200,
// Sceny TPDB/StashDB bez tube-linków nie są usable — zawsze filtrujemy.
@ -270,21 +276,31 @@ export function PerformerScenesScreen() {
</Pressable>
</View>
{tab === 'scenes' && !!tagsQuery.data?.items.length && (
<View style={styles.tagRow}>
{tagsQuery.data.items.map((t) => (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.tagRow}
>
{tagsQuery.data.items.map((t) => {
const active = selectedTag?.slug === t.slug;
return (
<Pressable
key={t.id}
style={styles.tagChip}
style={[styles.tagChip, active && styles.tagChipActive]}
onPress={() =>
navigation.push('TagScenes', { slug: t.slug, name: t.name })
setSelectedTag(active ? null : { slug: t.slug, name: t.name })
}
>
<Text style={styles.tagChipText} numberOfLines={1}>
{t.name}
<Text
style={[styles.tagChipText, active && styles.tagChipTextActive]}
numberOfLines={1}
>
{active ? `${t.name}` : t.name}
</Text>
</Pressable>
))}
</View>
);
})}
</ScrollView>
)}
</View>
}
@ -418,10 +434,10 @@ const styles = StyleSheet.create({
actionBtnTextPrimary: { color: theme.accent, fontWeight: '700', fontSize: 12 },
tagRow: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 6,
marginHorizontal: 4,
marginBottom: 10,
paddingHorizontal: 4,
paddingBottom: 10,
alignItems: 'center',
},
tagChip: {
backgroundColor: theme.card,
@ -430,9 +446,11 @@ const styles = StyleSheet.create({
borderRadius: 14,
paddingVertical: 4,
paddingHorizontal: 10,
maxWidth: 160,
maxWidth: 200,
},
tagChipActive: { backgroundColor: theme.accent, borderColor: theme.accent },
tagChipText: { color: theme.muted, fontSize: 12, fontWeight: '600' },
tagChipTextActive: { color: theme.fg, fontWeight: '700' },
tabRow: { flexDirection: 'row', gap: 8, marginBottom: 8 },
tabBtn: {
flex: 1,