fix(player): respect safe area in chapter list and refine UX

- Inset chapter list sheet by left/right/bottom safe-area2
- Remove dimmed backdrop so video stays visible behind the sheet
- Move chapter icon after Skip Intro / Credits / Next buttons
- Add pressed opacity feedback on chapter icon
- Drop unused chapterPositions prop from BottomControls
This commit is contained in:
Alex Kim
2026-06-02 19:48:56 +10:00
parent 88163eb531
commit bf061403fe
3 changed files with 29 additions and 20 deletions

View File

@@ -9,8 +9,10 @@ import type { ChapterInfo } from "@jellyfin/sdk/lib/generated-client/models";
import { memo, useEffect, useMemo, useRef } from "react";
import { useTranslation } from "react-i18next";
import { FlatList, Modal, Pressable, StyleSheet, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Text } from "@/components/common/Text";
import { Colors } from "@/constants/Colors";
import { useSettings } from "@/utils/atoms/settings";
import {
type ChapterEntry,
chapterStartsMs,
@@ -29,6 +31,7 @@ interface ChapterListProps {
}
const ROW_HEIGHT = 48;
const ZERO_INSETS = { top: 0, right: 0, bottom: 0, left: 0 };
function ChapterListComponent({
visible,
@@ -38,6 +41,10 @@ function ChapterListComponent({
onClose,
}: ChapterListProps) {
const { t } = useTranslation();
const { settings } = useSettings();
const insets = useSafeAreaInsets();
const safeArea =
(settings?.safeAreaInControlsEnabled ?? true) ? insets : ZERO_INSETS;
const listRef = useRef<FlatList<ChapterEntry>>(null);
const entries = useMemo(() => sortedChapters(chapters), [chapters]);
@@ -79,7 +86,17 @@ function ChapterListComponent({
supportedOrientations={["portrait", "landscape"]}
>
<Pressable onPress={onClose} style={styles.backdrop}>
<Pressable onPress={(e) => e.stopPropagation()} style={styles.sheet}>
<Pressable
onPress={(e) => e.stopPropagation()}
style={[
styles.sheet,
{
marginLeft: safeArea.left,
marginRight: safeArea.right,
paddingBottom: safeArea.bottom,
},
]}
>
<View style={styles.header}>
<Text style={styles.title}>{t("chapters.title")}</Text>
<Pressable
@@ -160,14 +177,12 @@ const styles = StyleSheet.create({
backdrop: {
flex: 1,
justifyContent: "flex-end",
backgroundColor: "rgba(0,0,0,0.6)",
},
sheet: {
backgroundColor: Colors.background,
borderTopLeftRadius: 16,
borderTopRightRadius: 16,
maxHeight: "70%",
paddingBottom: 24,
},
header: {
flexDirection: "row",

View File

@@ -75,9 +75,6 @@ interface BottomControlsProps {
minutes: number;
seconds: number;
};
// Chapter props
chapterPositions?: number[];
}
export const BottomControls: FC<BottomControlsProps> = ({
@@ -111,7 +108,6 @@ export const BottomControls: FC<BottomControlsProps> = ({
trickPlayUrl,
trickplayInfo,
time,
chapterPositions = [],
}) => {
const { settings } = useSettings();
const { t } = useTranslation();
@@ -188,17 +184,6 @@ export const BottomControls: FC<BottomControlsProps> = ({
) : null}
</View>
<View className='flex flex-row items-center space-x-2 shrink-0'>
{hasChapters && (
<Pressable
onPress={() => setChapterListVisible(true)}
hitSlop={10}
className='justify-center mr-4'
accessibilityRole='button'
accessibilityLabel={t("chapters.open")}
>
<Ionicons name='bookmarks' size={24} color='white' />
</Pressable>
)}
<SkipButton
showButton={showSkipButton}
onPress={skipIntro}
@@ -230,6 +215,17 @@ export const BottomControls: FC<BottomControlsProps> = ({
onPress={handleNextEpisodeManual}
/>
)}
{hasChapters && (
<Pressable
onPress={() => setChapterListVisible(true)}
hitSlop={10}
className='justify-center ml-4'
accessibilityRole='button'
accessibilityLabel={t("chapters.open")}
>
<Ionicons name='bookmarks' size={24} color='white' />
</Pressable>
)}
</View>
</View>
<View

View File

@@ -219,7 +219,6 @@ export const Controls: FC<Props> = ({
hasNextChapter,
goToPreviousChapter,
goToNextChapter,
chapterPositions,
} = useChapterNavigation({
chapters: item.Chapters,
progress,
@@ -585,7 +584,6 @@ export const Controls: FC<Props> = ({
trickPlayUrl={trickPlayUrl}
trickplayInfo={trickplayInfo}
time={isSliding || showRemoteBubble ? time : remoteTime}
chapterPositions={chapterPositions}
/>
</Animated.View>
</>