@@ -7,10 +7,11 @@
|
|||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
|
"ajv": "^8.17.1",
|
||||||
"materialize-css": "^1.0.0",
|
"materialize-css": "^1.0.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^19.1.0",
|
"react": "^19.2.3",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.2.3",
|
||||||
"react-materialize": "^3.10.0",
|
"react-materialize": "^3.10.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"sass": "^1.89.0",
|
"sass": "^1.89.0",
|
||||||
|
|||||||
37
src/App.js
37
src/App.js
@@ -1,5 +1,5 @@
|
|||||||
import "./App.css";
|
import "./App.css";
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import WaveForm from "./WaveForm";
|
import WaveForm from "./WaveForm";
|
||||||
import M from "materialize-css";
|
import M from "materialize-css";
|
||||||
import text from "./list.txt";
|
import text from "./list.txt";
|
||||||
@@ -13,11 +13,19 @@ import useBackgroundImages from "./hooks/useBackgroundImages";
|
|||||||
import Header from "./components/Header";
|
import Header from "./components/Header";
|
||||||
import TrackInfo from "./components/TrackInfo";
|
import TrackInfo from "./components/TrackInfo";
|
||||||
import AudioControls from "./components/AudioControls";
|
import AudioControls from "./components/AudioControls";
|
||||||
|
import StreamSelector from "./components/StreamSelector";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main App component
|
* Main App component
|
||||||
*/
|
*/
|
||||||
const App = () => {
|
const App = () => {
|
||||||
|
// State for current stream selection
|
||||||
|
const [currentStream, setCurrentStream] = useState({
|
||||||
|
id: 'stream-radio',
|
||||||
|
name: 'Stream Radio',
|
||||||
|
url: '/stream.mp3'
|
||||||
|
});
|
||||||
|
|
||||||
// Custom hook for managing background images
|
// Custom hook for managing background images
|
||||||
const { loadImages } = useBackgroundImages(text);
|
const { loadImages } = useBackgroundImages(text);
|
||||||
|
|
||||||
@@ -46,6 +54,26 @@ const App = () => {
|
|||||||
// Initialization flag to prevent multiple initializations
|
// Initialization flag to prevent multiple initializations
|
||||||
const initialized = useRef(false);
|
const initialized = useRef(false);
|
||||||
|
|
||||||
|
// Handle stream change
|
||||||
|
const handleStreamChange = (newStream) => {
|
||||||
|
const wasPlaying = !paused;
|
||||||
|
|
||||||
|
// Pause current playback
|
||||||
|
if (wasPlaying) {
|
||||||
|
pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update stream
|
||||||
|
setCurrentStream(newStream);
|
||||||
|
|
||||||
|
// Resume playback if was playing
|
||||||
|
if (wasPlaying) {
|
||||||
|
setTimeout(() => {
|
||||||
|
play();
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Initialize app and setup periodic data refresh
|
// Initialize app and setup periodic data refresh
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialized.current) return;
|
if (initialized.current) return;
|
||||||
@@ -100,8 +128,13 @@ const App = () => {
|
|||||||
onToggleMute={toggleMute}
|
onToggleMute={toggleMute}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<StreamSelector
|
||||||
|
currentStream={currentStream.id}
|
||||||
|
onStreamChange={handleStreamChange}
|
||||||
|
/>
|
||||||
|
|
||||||
<audio
|
<audio
|
||||||
src="/stream.mp3"
|
src={currentStream.url}
|
||||||
ref={audioElmRef}
|
ref={audioElmRef}
|
||||||
preload="none"
|
preload="none"
|
||||||
muted={muted}
|
muted={muted}
|
||||||
|
|||||||
87
src/components/StreamSelector.js
Archivo normal
87
src/components/StreamSelector.js
Archivo normal
@@ -0,0 +1,87 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamSelector component
|
||||||
|
* Displays a select dropdown to choose between different radio streams
|
||||||
|
*/
|
||||||
|
const StreamSelector = ({ currentStream, onStreamChange }) => {
|
||||||
|
const streams = [
|
||||||
|
{
|
||||||
|
id: 'stream-radio',
|
||||||
|
name: 'Stream Radio',
|
||||||
|
url: '/stream.mp3'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'canal-sur',
|
||||||
|
name: 'Canal Sur Radio',
|
||||||
|
url: 'https://rtva-live-radio.flumotion.com/rtva/csr.mp3'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'radio-andalucia',
|
||||||
|
name: 'Radio Andalucía Información',
|
||||||
|
url: 'https://rtva-live-radio.flumotion.com/rtva/rai.mp3'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const selectedStream = streams.find(stream => stream.id === e.target.value);
|
||||||
|
if (selectedStream) {
|
||||||
|
onStreamChange(selectedStream);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="stream-selector-container" style={{
|
||||||
|
margin: '20px auto',
|
||||||
|
maxWidth: '400px',
|
||||||
|
padding: '0 20px'
|
||||||
|
}}>
|
||||||
|
<div className="input-field">
|
||||||
|
<select
|
||||||
|
value={currentStream}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="browser-default"
|
||||||
|
style={{
|
||||||
|
display: 'block',
|
||||||
|
width: '100%',
|
||||||
|
padding: '10px 15px',
|
||||||
|
fontSize: '16px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
border: '1px solid rgba(255, 255, 255, 0.3)',
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||||
|
color: '#fff',
|
||||||
|
cursor: 'pointer',
|
||||||
|
outline: 'none',
|
||||||
|
transition: 'all 0.3s ease'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{streams.map(stream => (
|
||||||
|
<option
|
||||||
|
key={stream.id}
|
||||||
|
value={stream.id}
|
||||||
|
style={{ backgroundColor: '#333', color: '#fff' }}
|
||||||
|
>
|
||||||
|
{stream.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<label style={{
|
||||||
|
color: 'rgba(255, 255, 255, 0.7)',
|
||||||
|
fontSize: '14px',
|
||||||
|
marginTop: '5px',
|
||||||
|
display: 'block'
|
||||||
|
}}>
|
||||||
|
Selecciona una emisora
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
StreamSelector.propTypes = {
|
||||||
|
currentStream: PropTypes.string.isRequired,
|
||||||
|
onStreamChange: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default StreamSelector;
|
||||||
Referencia en una nueva incidencia
Block a user