feat: Enhance Chromecast functionality and UI improvements

- Implemented a retry mechanism for Chromecast device discovery with a maximum of 3 attempts.
- Added logging for discovered devices to aid in debugging.
- Updated Chromecast button interactions to streamline navigation to the casting player.
- Changed the color scheme for Chromecast components to a consistent purple theme.
- Modified the ChromecastDeviceSheet to sync volume slider with prop changes.
- Improved the ChromecastSettingsMenu to conditionally render audio and subtitle tracks based on availability.
- Updated translations for the casting player to include new strings for better user experience.
This commit is contained in:
Uruk
2026-01-22 18:57:56 +01:00
committed by Gauvain
parent d4f730fc54
commit 7589ccd284
9 changed files with 1135 additions and 475 deletions

View File

@@ -4,7 +4,7 @@
*/
import { Ionicons } from "@expo/vector-icons";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { Modal, Pressable, View } from "react-native";
import { Slider } from "react-native-awesome-slider";
import type { Device } from "react-native-google-cast";
@@ -19,6 +19,7 @@ interface ChromecastDeviceSheetProps {
onDisconnect: () => Promise<void>;
volume?: number;
onVolumeChange?: (volume: number) => Promise<void>;
showTechnicalInfo?: boolean;
}
export const ChromecastDeviceSheet: React.FC<ChromecastDeviceSheetProps> = ({
@@ -28,11 +29,17 @@ export const ChromecastDeviceSheet: React.FC<ChromecastDeviceSheetProps> = ({
onDisconnect,
volume = 0.5,
onVolumeChange,
showTechnicalInfo = false,
}) => {
const insets = useSafeAreaInsets();
const [isDisconnecting, setIsDisconnecting] = useState(false);
const volumeValue = useSharedValue(volume * 100);
// Sync volume slider with prop changes
useEffect(() => {
volumeValue.value = volume * 100;
}, [volume, volumeValue]);
const handleDisconnect = async () => {
setIsDisconnecting(true);
try {
@@ -55,9 +62,8 @@ export const ChromecastDeviceSheet: React.FC<ChromecastDeviceSheetProps> = ({
<Modal
visible={visible}
animationType='slide'
presentationStyle='pageSheet'
presentationStyle='formSheet'
onRequestClose={onClose}
transparent
>
<Pressable
style={{
@@ -90,7 +96,7 @@ export const ChromecastDeviceSheet: React.FC<ChromecastDeviceSheetProps> = ({
<View
style={{ flexDirection: "row", alignItems: "center", gap: 12 }}
>
<Ionicons name='tv' size={24} color='#e50914' />
<Ionicons name='tv' size={24} color='#a855f7' />
<Text style={{ color: "white", fontSize: 18, fontWeight: "600" }}>
Chromecast
</Text>
@@ -111,7 +117,7 @@ export const ChromecastDeviceSheet: React.FC<ChromecastDeviceSheetProps> = ({
</Text>
</View>
{device?.deviceId && (
{device?.deviceId && showTechnicalInfo && (
<View style={{ marginBottom: 20 }}>
<Text style={{ color: "#999", fontSize: 12, marginBottom: 4 }}>
Device ID
@@ -153,8 +159,8 @@ export const ChromecastDeviceSheet: React.FC<ChromecastDeviceSheetProps> = ({
theme={{
disableMinTrackTintColor: "#333",
maximumTrackTintColor: "#333",
minimumTrackTintColor: "#e50914",
bubbleBackgroundColor: "#e50914",
minimumTrackTintColor: "#a855f7",
bubbleBackgroundColor: "#a855f7",
}}
onValueChange={(value) => {
volumeValue.value = value;
@@ -171,7 +177,7 @@ export const ChromecastDeviceSheet: React.FC<ChromecastDeviceSheetProps> = ({
onPress={handleDisconnect}
disabled={isDisconnecting}
style={{
backgroundColor: "#e50914",
backgroundColor: "#a855f7",
padding: 16,
borderRadius: 8,
flexDirection: "row",

View File

@@ -41,7 +41,7 @@ export const ChromecastEpisodeList: React.FC<ChromecastEpisodeListProps> = ({
style={{
flexDirection: "row",
padding: 12,
backgroundColor: isCurrentEpisode ? "#e50914" : "transparent",
backgroundColor: isCurrentEpisode ? "#a855f7" : "transparent",
borderRadius: 8,
marginBottom: 8,
}}
@@ -131,7 +131,7 @@ export const ChromecastEpisodeList: React.FC<ChromecastEpisodeListProps> = ({
<Modal
visible={visible}
animationType='slide'
presentationStyle='pageSheet'
presentationStyle='formSheet'
onRequestClose={onClose}
>
<View

View File

@@ -95,9 +95,8 @@ export const ChromecastSettingsMenu: React.FC<ChromecastSettingsMenuProps> = ({
<Modal
visible={visible}
animationType='slide'
presentationStyle='pageSheet'
presentationStyle='formSheet'
onRequestClose={onClose}
transparent
>
<Pressable
style={{
@@ -172,16 +171,17 @@ export const ChromecastSettingsMenu: React.FC<ChromecastSettingsMenuProps> = ({
)}
</View>
{selectedMediaSource?.id === source.id && (
<Ionicons name='checkmark' size={20} color='#e50914' />
<Ionicons name='checkmark' size={20} color='#a855f7' />
)}
</Pressable>
))}
</View>
)}
{/* Audio Tracks */}
{renderSectionHeader("Audio", "musical-notes", "audio")}
{expandedSection === "audio" && (
{/* Audio Tracks - only show if more than one track */}
{audioTracks.length > 1 &&
renderSectionHeader("Audio", "musical-notes", "audio")}
{audioTracks.length > 1 && expandedSection === "audio" && (
<View style={{ paddingVertical: 8 }}>
{audioTracks.map((track) => (
<Pressable
@@ -214,16 +214,17 @@ export const ChromecastSettingsMenu: React.FC<ChromecastSettingsMenuProps> = ({
)}
</View>
{selectedAudioTrack?.index === track.index && (
<Ionicons name='checkmark' size={20} color='#e50914' />
<Ionicons name='checkmark' size={20} color='#a855f7' />
)}
</Pressable>
))}
</View>
)}
{/* Subtitle Tracks */}
{renderSectionHeader("Subtitles", "text", "subtitles")}
{expandedSection === "subtitles" && (
{/* Subtitle Tracks - only show if subtitles available */}
{subtitleTracks.length > 0 &&
renderSectionHeader("Subtitles", "text", "subtitles")}
{subtitleTracks.length > 0 && expandedSection === "subtitles" && (
<View style={{ paddingVertical: 8 }}>
<Pressable
onPress={() => {
@@ -243,7 +244,7 @@ export const ChromecastSettingsMenu: React.FC<ChromecastSettingsMenuProps> = ({
>
<Text style={{ color: "white", fontSize: 15 }}>None</Text>
{selectedSubtitleTrack === null && (
<Ionicons name='checkmark' size={20} color='#e50914' />
<Ionicons name='checkmark' size={20} color='#a855f7' />
)}
</Pressable>
{subtitleTracks.map((track) => (
@@ -278,7 +279,7 @@ export const ChromecastSettingsMenu: React.FC<ChromecastSettingsMenuProps> = ({
)}
</View>
{selectedSubtitleTrack?.index === track.index && (
<Ionicons name='checkmark' size={20} color='#e50914' />
<Ionicons name='checkmark' size={20} color='#a855f7' />
)}
</Pressable>
))}
@@ -309,7 +310,7 @@ export const ChromecastSettingsMenu: React.FC<ChromecastSettingsMenuProps> = ({
{speed === 1 ? "Normal" : `${speed}x`}
</Text>
{playbackSpeed === speed && (
<Ionicons name='checkmark' size={20} color='#e50914' />
<Ionicons name='checkmark' size={20} color='#a855f7' />
)}
</Pressable>
))}
@@ -343,7 +344,7 @@ export const ChromecastSettingsMenu: React.FC<ChromecastSettingsMenuProps> = ({
width: 50,
height: 30,
borderRadius: 15,
backgroundColor: showTechnicalInfo ? "#e50914" : "#333",
backgroundColor: showTechnicalInfo ? "#a855f7" : "#333",
justifyContent: "center",
alignItems: showTechnicalInfo ? "flex-end" : "flex-start",
padding: 2,