mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-06-02 12:08:37 +01:00
feat(casting): show stop button when playing a movie
This commit is contained in:
@@ -509,19 +509,18 @@ export default function CastingPlayerScreen() {
|
|||||||
/>
|
/>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
{/* Fixed 4-button control row for episodes - positioned independently */}
|
{/* Fixed control row - positioned independently. Episode-specific
|
||||||
{currentItem.Type === "Episode" && (
|
buttons are conditional inside; Stop is always available. */}
|
||||||
<CastPlayerEpisodeControls
|
<CastPlayerEpisodeControls
|
||||||
insetBottom={insets.bottom}
|
insetBottom={insets.bottom}
|
||||||
currentItemId={currentItem.Id}
|
currentItemId={currentItem.Id}
|
||||||
episodes={episodes}
|
episodes={episodes}
|
||||||
nextEpisode={nextEpisode}
|
nextEpisode={nextEpisode}
|
||||||
remoteMediaClient={remoteMediaClient}
|
remoteMediaClient={remoteMediaClient}
|
||||||
onPressEpisodes={() => setShowEpisodeList(true)}
|
onPressEpisodes={() => setShowEpisodeList(true)}
|
||||||
loadEpisode={loadEpisode}
|
loadEpisode={loadEpisode}
|
||||||
router={router}
|
router={router}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Fixed bottom controls area */}
|
{/* Fixed bottom controls area */}
|
||||||
<View
|
<View
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Casting Player Episode Controls
|
* Casting Player Episode Controls
|
||||||
* Fixed 4-button control row for episodes: episode list, previous, next, stop.
|
* Fixed control row: episode list, previous, next, stop.
|
||||||
|
* Episode-specific buttons (list / previous / next) are conditional;
|
||||||
|
* Stop is always rendered so movies still get a Stop button.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
@@ -38,6 +40,26 @@ export function CastPlayerEpisodeControls({
|
|||||||
loadEpisode,
|
loadEpisode,
|
||||||
router,
|
router,
|
||||||
}: CastPlayerEpisodeControlsProps) {
|
}: CastPlayerEpisodeControlsProps) {
|
||||||
|
const hasEpisodeList = episodes.length > 0;
|
||||||
|
const hasPrevious = episodes.findIndex((ep) => ep.Id === currentItemId) > 0;
|
||||||
|
const hasNext = nextEpisode != null;
|
||||||
|
|
||||||
|
// Count of buttons actually rendered (Stop is always rendered).
|
||||||
|
const buttonCount =
|
||||||
|
1 + (hasEpisodeList ? 1 : 0) + (hasPrevious ? 1 : 0) + (hasNext ? 1 : 0);
|
||||||
|
|
||||||
|
// Each button stretches evenly only when the row holds more than one;
|
||||||
|
// a lone Stop button keeps its intrinsic size and stays centered.
|
||||||
|
const buttonStyle = {
|
||||||
|
...(buttonCount > 1 ? { flex: 1 } : {}),
|
||||||
|
backgroundColor: "#1a1a1a",
|
||||||
|
padding: 12,
|
||||||
|
borderRadius: 12,
|
||||||
|
flexDirection: "row" as const,
|
||||||
|
justifyContent: "center" as const,
|
||||||
|
alignItems: "center" as const,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
style={{
|
style={{
|
||||||
@@ -52,24 +74,15 @@ export function CastPlayerEpisodeControls({
|
|||||||
paddingHorizontal: 20,
|
paddingHorizontal: 20,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Episodes button */}
|
{/* Episodes button - only rendered when an episode list exists (not for movies) */}
|
||||||
<Pressable
|
{hasEpisodeList && (
|
||||||
onPress={onPressEpisodes}
|
<Pressable onPress={onPressEpisodes} style={buttonStyle}>
|
||||||
style={{
|
<Ionicons name='list' size={22} color='white' />
|
||||||
flex: 1,
|
</Pressable>
|
||||||
backgroundColor: "#1a1a1a",
|
)}
|
||||||
padding: 12,
|
|
||||||
borderRadius: 12,
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Ionicons name='list' size={22} color='white' />
|
|
||||||
</Pressable>
|
|
||||||
|
|
||||||
{/* Previous episode button - only rendered when a previous episode exists */}
|
{/* Previous episode button - only rendered when a previous episode exists */}
|
||||||
{episodes.findIndex((ep) => ep.Id === currentItemId) > 0 && (
|
{hasPrevious && (
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
const currentIndex = episodes.findIndex(
|
const currentIndex = episodes.findIndex(
|
||||||
@@ -79,43 +92,27 @@ export function CastPlayerEpisodeControls({
|
|||||||
await loadEpisode(episodes[currentIndex - 1]);
|
await loadEpisode(episodes[currentIndex - 1]);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
style={buttonStyle}
|
||||||
flex: 1,
|
|
||||||
backgroundColor: "#1a1a1a",
|
|
||||||
padding: 12,
|
|
||||||
borderRadius: 12,
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Ionicons name='play-skip-back' size={22} color='white' />
|
<Ionicons name='play-skip-back' size={22} color='white' />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Next episode button - only rendered when a next episode exists */}
|
{/* Next episode button - only rendered when a next episode exists */}
|
||||||
{nextEpisode && (
|
{hasNext && (
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
if (nextEpisode) {
|
if (nextEpisode) {
|
||||||
await loadEpisode(nextEpisode);
|
await loadEpisode(nextEpisode);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
style={buttonStyle}
|
||||||
flex: 1,
|
|
||||||
backgroundColor: "#1a1a1a",
|
|
||||||
padding: 12,
|
|
||||||
borderRadius: 12,
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Ionicons name='play-skip-forward' size={22} color='white' />
|
<Ionicons name='play-skip-forward' size={22} color='white' />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Stop playback button - stops media but stays connected to Chromecast */}
|
{/* Stop playback button - always rendered; stops media but stays connected to Chromecast */}
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={async () => {
|
onPress={async () => {
|
||||||
try {
|
try {
|
||||||
@@ -140,15 +137,7 @@ export function CastPlayerEpisodeControls({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
style={{
|
style={buttonStyle}
|
||||||
flex: 1,
|
|
||||||
backgroundColor: "#1a1a1a",
|
|
||||||
padding: 12,
|
|
||||||
borderRadius: 12,
|
|
||||||
flexDirection: "row",
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Ionicons name='stop-circle' size={22} color='white' />
|
<Ionicons name='stop-circle' size={22} color='white' />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|||||||
Reference in New Issue
Block a user