Add chromecast seek bar and api, move volume component to separate file
This commit is contained in:
parent
3d1e78f9af
commit
250cf1f778
@ -54,6 +54,12 @@ mutation {
|
||||
}
|
||||
`;
|
||||
|
||||
const SEEK = (uid, value) => gql`
|
||||
mutation {
|
||||
chromecastSeek(uid:"${uid}", value:${value})
|
||||
}
|
||||
`;
|
||||
|
||||
const MEDIA_STATUS = () => gql`
|
||||
subscription {
|
||||
mediaStatus {
|
||||
@ -106,3 +112,7 @@ export const chromecastPlay = (uid) => client.mutate({
|
||||
export const chromecastVolumeChange = (uid, volume) => client.mutate({
|
||||
mutation: VOLUME_CHANGE(uid, volume),
|
||||
});
|
||||
|
||||
export const chromecastSeek = (uid, value) => client.mutate({
|
||||
mutation: SEEK(uid, value),
|
||||
});
|
||||
|
@ -1,27 +1,12 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Button, Card, Slider } from 'antd';
|
||||
import { Button, Card } from 'antd';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faPlayCircle, faPauseCircle } from '@fortawesome/free-regular-svg-icons';
|
||||
import chromecastStore from '../store/chromecastStore';
|
||||
import { chromecastPause, chromecastPlay } from '../service/chromecast';
|
||||
import TimeDisplay from './timeDisplay';
|
||||
import { chromecastPause, chromecastPlay, chromecastVolumeChange } from '../service/chromecast';
|
||||
|
||||
|
||||
const VolumeComponent = ({ uid, volumeLevel }) => {
|
||||
let id = null;
|
||||
const handleVolumeChange = (value) => {
|
||||
if (id) clearTimeout(id);
|
||||
id = setTimeout(() => {
|
||||
chromecastVolumeChange(uid, value * 0.01);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
useEffect(() => () => clearTimeout(id));
|
||||
|
||||
return (
|
||||
<Slider defaultValue={volumeLevel * 100} onChange={handleVolumeChange} />
|
||||
);
|
||||
};
|
||||
import VolumeComponent from './volume';
|
||||
import TimeProgressComponent from './timeProgress';
|
||||
|
||||
const ChromecastDeviceComponent = () => {
|
||||
const [chromecastList, setChromecastList] = useState(chromecastStore.chromecast);
|
||||
@ -77,6 +62,12 @@ const ChromecastDevice = ({ device }) => {
|
||||
duration={status.duration}
|
||||
playerState={status.playerState}
|
||||
/>
|
||||
<TimeProgressComponent
|
||||
uid={device.uuid}
|
||||
currentTime={status.currentTime}
|
||||
duration={status.duration}
|
||||
playerState={status.playerState}
|
||||
/>
|
||||
<VolumeComponent uid={device.uuid} volumeLevel={castStatus.volumeLevel} />
|
||||
<Button type="link" icon={<FontAwesomeIcon icon={faPauseCircle} onClick={handlePauseClick} size="2x" />} />
|
||||
</div>
|
||||
@ -91,6 +82,12 @@ const ChromecastDevice = ({ device }) => {
|
||||
duration={status.duration}
|
||||
playerState={status.playerState}
|
||||
/>
|
||||
<TimeProgressComponent
|
||||
uid={device.uuid}
|
||||
currentTime={status.currentTime}
|
||||
duration={status.duration}
|
||||
playerState={status.playerState}
|
||||
/>
|
||||
<VolumeComponent uid={device.uuid} volumeLevel={castStatus.volumeLevel} />
|
||||
<Button type="link" icon={<FontAwesomeIcon icon={faPlayCircle} onClick={handlePlayClick} size="2x" />} />
|
||||
</div>
|
||||
|
@ -11,7 +11,10 @@ const TimeDisplay = ({ currentTime, duration, playerState }) => {
|
||||
if (playerState === 'PLAYING') {
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
const current = timeData[2] + 1;
|
||||
let current = timeData[2] + 1;
|
||||
if (Math.abs(current - currentTime) > 10) {
|
||||
current = Math.round(currentTime);
|
||||
}
|
||||
setTimeData([
|
||||
movieTimeFormat(current),
|
||||
movieTimeFormat(Math.round(duration)),
|
||||
|
47
frontend/src/view/timeProgress.jsx
Normal file
47
frontend/src/view/timeProgress.jsx
Normal file
@ -0,0 +1,47 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Slider } from 'antd';
|
||||
import { chromecastSeek } from '../service/chromecast';
|
||||
import movieTimeFormat from '../formatter/movieTimeFormat';
|
||||
|
||||
|
||||
const TimeProgressComponent = ({
|
||||
uid,
|
||||
currentTime,
|
||||
duration,
|
||||
playerState,
|
||||
}) => {
|
||||
const [time, setTime] = useState(Math.floor(currentTime));
|
||||
|
||||
if (playerState === 'PLAYING') {
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
let current = time + 1;
|
||||
if (Math.abs(current - currentTime) > 10) {
|
||||
current = Math.round(currentTime);
|
||||
}
|
||||
setTime(current);
|
||||
}, 1000);
|
||||
return () => clearTimeout(timer);
|
||||
});
|
||||
}
|
||||
|
||||
const handleSeek = (value) => {
|
||||
chromecastSeek(uid, value);
|
||||
};
|
||||
|
||||
const handleChange = (value) => {
|
||||
setTime(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Slider
|
||||
max={Math.floor(duration)}
|
||||
value={time}
|
||||
onChange={handleChange}
|
||||
onAfterChange={handleSeek}
|
||||
tipFormatter={movieTimeFormat}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default TimeProgressComponent;
|
21
frontend/src/view/volume.jsx
Normal file
21
frontend/src/view/volume.jsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Slider } from 'antd';
|
||||
import { chromecastVolumeChange } from '../service/chromecast';
|
||||
|
||||
const VolumeComponent = ({ uid, volumeLevel }) => {
|
||||
let id = null;
|
||||
const handleVolumeChange = (value) => {
|
||||
if (id) clearTimeout(id);
|
||||
id = setTimeout(() => {
|
||||
chromecastVolumeChange(uid, value * 0.01);
|
||||
}, 500);
|
||||
};
|
||||
|
||||
useEffect(() => () => clearTimeout(id));
|
||||
|
||||
return (
|
||||
<Slider defaultValue={volumeLevel * 100} onChange={handleVolumeChange} />
|
||||
);
|
||||
};
|
||||
|
||||
export default VolumeComponent;
|
@ -141,6 +141,26 @@ class ChromecastVolumeChange(graphene.Mutation):
|
||||
data.device.set_volume(volume)
|
||||
return True
|
||||
|
||||
class ChromecastSeek(graphene.Mutation):
|
||||
"""Chromecast volume change"""
|
||||
class Arguments:
|
||||
"""Chromecast volume change uid and volume float value"""
|
||||
uid = graphene.String(required=True)
|
||||
value = graphene.Float(required=True)
|
||||
|
||||
Output = graphene.Boolean
|
||||
|
||||
def mutate(self,
|
||||
info: ResolveInfo,
|
||||
uid: graphene.String,
|
||||
value: graphene.Float) -> graphene.Boolean: # pylint: disable=W0622
|
||||
"""Method to volume change uid and volume float value"""
|
||||
if uid not in cache.CHROMECAST:
|
||||
raise error.ChromecastUUIDError(uid=uid)
|
||||
data = cache.CHROMECAST[uid]
|
||||
data.device.media_controller.seek(value)
|
||||
return True
|
||||
|
||||
|
||||
class ChromecastDevice:
|
||||
"""Device with api and interface data"""
|
||||
|
@ -18,3 +18,4 @@ class Mutation(graphene.ObjectType):
|
||||
chromecastPause = chromecast.ChromecastPause.Field()
|
||||
chromecastPlay = chromecast.ChromecastPlay.Field()
|
||||
chromecastVolumeChange = chromecast.ChromecastVolumeChange.Field()
|
||||
chromecastSeek = chromecast.ChromecastSeek.Field()
|
||||
|
Loading…
Reference in New Issue
Block a user