Files
Iris/src/js/components/Snapcast.js

299 lines
9.3 KiB
JavaScript
Raw Normal View History

import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { Link, hashHistory } from 'react-router'
import ArtistSentence from './ArtistSentence'
import VolumeControl from './Fields/VolumeControl'
import LatencyControl from './Fields/LatencyControl'
import TextField from './Fields/TextField'
2018-04-29 21:10:57 +12:00
import DropdownField from './Fields/DropdownField'
2018-03-23 16:54:56 +13:00
import * as helpers from '../helpers'
import * as coreActions from '../services/core/actions'
import * as uiActions from '../services/ui/actions'
import * as pusherActions from '../services/pusher/actions'
import * as snapcastActions from '../services/snapcast/actions'
class Snapcast extends React.Component{
constructor(props){
2018-03-23 16:54:56 +13:00
super(props);
}
2018-03-21 21:40:47 +13:00
componentDidMount(){
2018-03-26 10:36:13 +13:00
if (this.props.pusher_connected && this.props.snapcast_enabled){
this.props.snapcastActions.getServer();
2018-03-21 21:40:47 +13:00
}
}
componentWillReceiveProps(newProps){
2018-03-26 10:36:13 +13:00
// Just connected
if (newProps.snapcast_enabled && !this.props.pusher_connected && newProps.pusher_connected){
this.props.snapcastActions.getServer();
2018-04-19 06:20:54 +12:00
// Just enabled
// This is the more probable scenario as we don't know if we're enabled until pusher connects
// and then gets the config from the server
} else if (!this.props.snapcast_enabled && newProps.snapcast_enabled && newProps.pusher_connected){
this.props.snapcastActions.getServer();
2018-03-21 21:40:47 +13:00
}
}
renderClientsList(group, groups){
if (!group.clients || group.clients.length <= 0){
return (
<div className="text grey-text">
No clients
</div>
);
}
return (
2018-09-24 16:10:42 +12:00
<div className="list snapcast__clients">
{
group.clients.map(client => {
var name = client.config.name ? client.config.name : client.host.name;
var groups_dropdown = [];
for (var i = 0; i < groups.length; i++){
// Don't add our existing group
if (groups[i].id !== group.id){
groups_dropdown.push({
2018-05-03 07:56:48 +12:00
label: (groups[i].name ? groups[i].name : 'Group '+groups[i].id.substring(0,3)),
value: groups[i].id
});
}
}
// And append with 'New group' (which is actually
// the existing group and middleware handles the behavior shift)
groups_dropdown.push({
label: 'New group',
2018-05-09 14:09:20 +12:00
value: group.id,
className: 'grey-text'
});
return (
2018-09-24 16:10:42 +12:00
<div className={"list-item snapcast__client "+(client.connected ? "snapcast__client--connected" : "snapcast__client--disconnected")} key={client.id}>
<div className="col name snapcast__client__name">
<DropdownField
2018-09-24 16:10:42 +12:00
className="snapcast__client__group-dropdown-field"
2018-06-01 16:54:32 +12:00
icon="settings"
name="Group"
no_label
no_status_icon
value={group.id}
options={groups_dropdown}
2018-05-09 14:09:20 +12:00
uid={group.id+"_"+client.id}
handleChange={value => {this.props.snapcastActions.setClientGroup(client.id, value); this.props.uiActions.hideContextMenu()}}
/>
<TextField
onChange={value => this.props.snapcastActions.setClientName(client.id, value)}
value={name}
/>
</div>
2018-09-24 16:10:42 +12:00
<div className="col snapcast__client__volume">
<VolumeControl
2018-09-24 16:10:42 +12:00
className="snapcast__client__volume-control"
volume={client.config.volume.percent}
mute={client.config.volume.muted}
onVolumeChange={percent => this.props.snapcastActions.setClientVolume(client.id, percent)}
onMuteChange={mute => this.props.snapcastActions.setClientMute(client.id, mute)}
/>
</div>
2018-09-24 16:10:42 +12:00
<div className="col snapcast__client__latency">
<LatencyControl
max="100"
value={client.config.latency}
onChange={value => this.props.snapcastActions.setClientLatency(client.id, parseInt(value))}
/>
<TextField
className="tiny"
2018-08-27 08:21:41 +12:00
type="number"
onChange={value => this.props.snapcastActions.setClientLatency(client.id, parseInt(value))}
value={String(client.config.latency)}
/>
</div>
</div>
);
})
}
</div>
);
}
render(){
if (!this.props.snapcast_enabled){
return (
2018-09-18 16:59:10 +12:00
<p className="message warning">To enable Snapcast, edit your <code>mopidy.conf</code> file</p>
)
}
if (!this.props.clients || !this.props.groups){
return (
<div className="lazy-loader body-loader loading">
<div className="loader"></div>
</div>
)
}
2018-04-29 21:10:57 +12:00
var streams = [];
for (var key in this.props.streams){
if (this.props.streams.hasOwnProperty(key)){
streams.push(this.props.streams[key]);
2018-04-29 21:10:57 +12:00
}
}
2018-03-22 16:59:04 +13:00
// Construct a simple array of our groups index
var groups = [];
for (var group_id in this.props.groups){
if (this.props.groups.hasOwnProperty(group_id)){
var group = this.props.groups[group_id];
2018-03-22 16:59:04 +13:00
// Merge the group's clients into this group (also as a simple array)
var clients = [];
for (var i = 0; i < group.clients_ids.length; i++){
if (this.props.clients.hasOwnProperty(group.clients_ids[i])){
var client = this.props.clients[group.clients_ids[i]];
if (client.connected || this.props.show_disconnected_clients){
clients.push(client);
}
}
2018-03-22 16:59:04 +13:00
}
2018-03-22 16:59:04 +13:00
groups.push(Object.assign(
{},
group,
{
clients: clients
}
));
}
}
return (
<div className="snapcast">
<div className="field checkbox">
<div className="name">
Display
</div>
<div className="input">
<button
className="small"
onClick={e => this.props.snapcastActions.getServer()}>
Refresh
</button>
<label>
<input
type="checkbox"
name="show_disconnected_clients"
checked={this.props.show_disconnected_clients}
onChange={e => this.props.uiActions.set({ snapcast_show_disconnected_clients: !this.props.show_disconnected_clients })} />
<span className="label">
Show disconnected clients
</span>
</label>
</div>
</div>
2018-09-24 16:10:42 +12:00
<div className="snapcast__groups">
{
groups.map(group => {
2018-05-02 16:14:53 +12:00
// Average our clients' volume for an overall group volume
var group_volume = 0;
for (var i = 0; i < group.clients.length; i++){
var client = group.clients[i];
group_volume += client.config.volume.percent;
}
group_volume = group_volume / group.clients.length;
2018-05-02 16:14:53 +12:00
return (
2018-09-24 16:10:42 +12:00
<div className="snapcast__group" key={group.id}>
<div className="field">
<div className="name">
Name
</div>
<div className="input">
<div className="text">
{group.name ? group.name : 'Group '+group.id.substring(0,3)} &nbsp;
<span className="grey-text">({group.id})</span>
</div>
2018-04-30 20:34:15 +12:00
</div>
</div>
<div className="field dropdown">
<div className="name">
Stream
</div>
<div className="input">
<select onChange={e => this.props.snapcastActions.setGroupStream(group.id, e.target.value)} value={group.stream_id}>
{
streams.map(stream => {
return (
<option value={stream.id} key={stream.id}>
{stream.id} ({stream.status})
</option>
);
})
}
</select>
</div>
2018-05-01 21:03:05 +12:00
</div>
<div className="field">
<div className="name">
Volume
</div>
<div className="input">
<VolumeControl
2018-09-24 16:10:42 +12:00
className="snapcast__group__volume-control"
volume={group_volume}
mute={group.muted}
onVolumeChange={(percent, old_percent) => this.props.snapcastActions.setGroupVolume(group.id, percent, old_percent)}
onMuteChange={mute => this.props.snapcastActions.setGroupMute(group.id, mute)}
/>
</div>
2018-04-18 17:01:57 +12:00
</div>
<div className="field">
<div className="name">
Clients
</div>
<div className="input">
{this.renderClientsList(group, groups)}
</div>
2018-04-18 17:01:57 +12:00
</div>
2018-03-23 16:54:56 +13:00
</div>
);
})
}
</div>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
return {
2018-03-26 10:36:13 +13:00
snapcast_enabled: state.pusher.config.snapcast_enabled,
2018-03-21 21:40:47 +13:00
pusher_connected: state.pusher.connected,
show_disconnected_clients: (state.ui.snapcast_show_disconnected_clients !== undefined ? state.ui.snapcast_show_disconnected_clients : false),
streams: (state.snapcast.streams ? state.snapcast.streams : null),
groups: (state.snapcast.groups ? state.snapcast.groups : null),
clients: (state.snapcast.clients ? state.snapcast.clients : null)
}
}
const mapDispatchToProps = (dispatch) => {
return {
coreActions: bindActionCreators(coreActions, dispatch),
uiActions: bindActionCreators(uiActions, dispatch),
snapcastActions: bindActionCreators(snapcastActions, dispatch),
pusherActions: bindActionCreators(pusherActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Snapcast)