Remapping store

This commit is contained in:
James Barnsley
2018-09-25 17:00:04 +12:00
parent 69ce3d71a4
commit efcdfd79fc
8 changed files with 14569 additions and 11030 deletions

View File

@ -74,25 +74,6 @@ class Snapcast extends React.Component{
{
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({
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',
value: group.id,
className: 'grey-text'
});
var class_name = "list__item snapcast__client";
if (client.connected){
@ -104,58 +85,118 @@ class Snapcast extends React.Component{
if (this.state.clients_expanded.includes(client.id)){
return (
<div className={class_name+" snapcast__client--expanded"} key={client.id}>
<div className="snapcast__client__expander" onClick={e => this.toggleClientExpanded(client.id)}>
<Icon name="check" />
<div className="snapcast__client__header" onClick={e => this.toggleClientExpanded(client.id)}>
{name}
<div className="snapcast__client__header__icons">
{!client.connected ? <Icon name="power_off" className="disconnected" /> : null}
<Icon name="expand_less" />
</div>
</div>
<div className="snapcast__client__name">
<TextField
onChange={value => this.props.snapcastActions.setClientName(client.id, value)}
value={name}
/>
<DropdownField
className="snapcast__client__group-field"
icon="folder"
name="Group"
no_label
no_status_icon
value={group.id}
options={groups_dropdown}
uid={group.id+"_"+client.id}
handleChange={value => {this.props.snapcastActions.setClientGroup(client.id, value); this.props.uiActions.hideContextMenu()}}
/>
</div>
<div className="snapcast__client__volume">
<VolumeControl
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>
<div className="snapcast__client__latency">
<LatencyControl
max="100"
value={client.config.latency}
onChange={value => this.props.snapcastActions.setClientLatency(client.id, parseInt(value))}
/>
<TextField
className="tiny"
type="number"
onChange={value => this.props.snapcastActions.setClientLatency(client.id, parseInt(value))}
value={String(client.config.latency)}
/>
<div className="snapcast__client__details">
<div className="field">
<div className="name">
Name
</div>
<div className="input">
<TextField
onChange={value => this.props.snapcastActions.setClientName(client.id, value)}
value={name}
/>
</div>
</div>
<div className="field dropdown">
<div className="name">
Group
</div>
<div className="input">
<select onChange={e => this.props.snapcastActions.setClientGroup(client.id, e.target.value)} value={group.id}>
{
groups.map(group => {
return (
<option value={group.id} key={group.id}>
{group.name ? group.name : 'Group '+group.id.substring(0,3)}
</option>
);
})
}
<option value={group.id}>
New group
</option>
</select>
</div>
</div>
<div className="snapcast__client__volume field">
<div className="name">
Volume
</div>
<div className="input">
<VolumeControl
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>
</div>
<div className="snapcast__client__latency field">
<div className="name">
Latency
</div>
<div className="input">
<LatencyControl
max="100"
value={client.config.latency}
onChange={value => this.props.snapcastActions.setClientLatency(client.id, parseInt(value))}
/>
<TextField
className="tiny"
type="number"
onChange={value => this.props.snapcastActions.setClientLatency(client.id, parseInt(value))}
value={String(client.config.latency)}
/>
</div>
</div>
<div className="field">
<div className="name tooltip">
Power on command
<span className="tooltip__content">
Fire this HTTP request to turn power on
</span>
</div>
<div className="input">
<TextField
onChange={value => console.log(value)}
value="http://localhost:8080/sendCommand/power_on"
/>
</div>
</div>
<div className="field">
<div className="name tooltip">
Power off command
<span className="tooltip__content">
Fire this HTTP request to turn power off
</span>
</div>
<div className="input">
<TextField
onChange={value => console.log(value)}
value="http://localhost:8080/sendCommand/power_off"
/>
</div>
</div>
</div>
</div>
);
} else {
return (
<div className={class_name} key={client.id}>
<div className="snapcast__client__expander" onClick={e => this.toggleClientExpanded(client.id)}>
<Icon name="edit" />
</div>
<div className="snapcast__client__name">
<div className={class_name+" snapcast__client--collapsed"} key={client.id}>
<div className="snapcast__client__header" onClick={e => this.toggleClientExpanded(client.id)}>
{name}
<div className="snapcast__client__header__icons">
{!client.connected ? <Icon name="power_off" className="disconnected" /> : null}
<Icon name="expand_more" />
</div>
</div>
</div>
);

View File

@ -50,13 +50,6 @@ export function getServer(){
}
}
export function serverLoaded(server){
return {
type: 'SNAPCAST_SERVER_LOADED',
server: server
}
}
export function setClientName(id, name){
return {
type: 'SNAPCAST_SET_CLIENT_NAME',
@ -129,3 +122,51 @@ export function setGroupVolume(id, percent, old_percent = 0){
}
}
/**
* Record loaders
*
* We've got a loaded record, now we just need to plug it in to our state and stores.
**/
export function serverLoaded(server){
return serversLoaded([server]);
}
export function serversLoaded(servers){
return {
type: 'SNAPCAST_SERVERS_LOADED',
servers: servers
}
}
export function clientLoaded(client){
return clientsLoaded([client]);
}
export function clientsLoaded(clients){
return {
type: 'SNAPCAST_CLIENTS_LOADED',
clients: clients
}
}
export function groupLoaded(group){
return groupsLoaded([group]);
}
export function groupsLoaded(groups){
return {
type: 'SNAPCAST_SERVERS_LOADED',
servers: group
}
}
export function streamLoaded(stream){
return streamsLoaded([stream]);
}
export function streamsLoaded(streams){
return {
type: 'SNAPCAST_STREAMS_LOADED',
streams: streams
}
}

View File

@ -2,31 +2,27 @@
export default function reducer(snapcast = {}, action){
switch (action.type){
case 'SNAPCAST_SERVER_LOADED':
return Object.assign({}, snapcast, {
streams: action.streams,
groups: action.groups,
clients: action.clients
});
case 'SNAPCAST_CLIENTS_LOADED':
var clients = Object.assign({}, snapcast.clients);
for (var client of action.clients){
clients[client.uri] = client;
}
return Object.assign({}, snapcast, { clients: clients });
case 'SNAPCAST_GROUP_UPDATED':
case 'SNAPCAST_SOURCES_LOADED':
var sources = Object.assign({}, snapcast.sources);
for (var source of action.sources){
sources[source.uri] = source;
}
return Object.assign({}, snapcast, { sources: sources });
case 'SNAPCAST_GROUPS_LOADED':
var groups = Object.assign({}, snapcast.groups);
var group = groups[action.key];
groups[action.key] = Object.assign({}, group, action.group);
for (var group of action.groups){
groups[group.uri] = group;
}
return Object.assign({}, snapcast, { groups: groups });
case 'SNAPCAST_CLIENT_UPDATED':
var clients = Object.assign({}, snapcast.clients);
var client = clients[action.key];
client.config = Object.assign({}, client.config, action.client.config);
clients[action.key] = client;
return Object.assign({}, snapcast, { clients: clients });
case 'SNAPCAST_CLIENT_REMOVED':
var clients = Object.assign({}, snapcast.clients);
delete clients[action.key];
return Object.assign({}, snapcast, { clients: clients });
default:
return snapcast
}

View File

@ -44,43 +44,55 @@
&__client {
@include clearfix();
position: relative;
padding: 14px 10px;
padding: 0;
&--disconnected {
opacity: 0.5;
.snapcast__client__header {
opacity: 0.5;
}
}
&--expanded {
.snapcast__client__name {
margin-top: -10px;
margin-right: 30px;
margin-left: -14px;
margin-bottom: 20px;
background: rgba(255,255,255,0.1);
.light-theme & {
background: rgba(0,0,0,0.1);
}
}
&__name {
margin-right: 40px;
padding-right: 50px;
position: relative;
display: block;
box-sizing: border-box;
border: 0;
&--collapsed {
.snapcast__client__header:hover {
background: rgba(255,255,255,0.03);
input {
width: 100%;
padding-right: 30px;
.light-theme & {
background: rgba(0,0,0,0.03);
}
}
}
&__expander {
position: absolute;
top: 0;
right: 0;
padding: 14px;
&__header {
font-weight: 500;
cursor: pointer;
z-index: 2;
position: relative;
padding: 14px 10px;
&__icons {
position: absolute;
top: 0;
right: 0;
cursor: pointer;
z-index: 2;
padding: 14px 10px;
.icon {
padding-left: 6px;
}
}
}
&__details {
position: relative;
padding: 0 14px 14px 14px;
}
&__group-field {
@ -93,11 +105,6 @@
}
}
&__volume {
width: 49%;
float: left;
}
&__volume-control {
padding-top: 11px;
padding-right: 10px;
@ -118,11 +125,6 @@
}
&__latency {
@include clearfix();
width: 49%;
padding-left: 2%;
float: left;
input[type="number"] {
width: 20%;
}