Client commands stored in localStorage

This commit is contained in:
James Barnsley
2018-09-28 16:02:53 +12:00
parent 7ef02105b5
commit c147730579
14 changed files with 14358 additions and 10919 deletions

View File

@ -192,6 +192,14 @@ class IrisCore(object):
callback = kwargs.get('callback', None)
data = kwargs.get('data', {})
if (not self.config['iris']['broadlink_enabled']):
error = {'message': 'Broadlink API not enabled'}
if (callback):
callback(False, error)
else:
return error
# Use client_id and client_secret from config
# This was introduced in Mopidy-Spotify 3.1.0
url = 'http://'+self.config['iris']['broadlink_host']+':'+str(self.config['iris']['broadlink_port'])+"/"

View File

@ -3009,6 +3009,33 @@ select {
select:focus, .light-theme
select:active {
background: #eeeae7; }
textarea::placeholder,
input[type="text"]::placeholder,
input[type="email"]::placeholder,
input[type="number"]::placeholder,
input[type="email"]::placeholder,
input[type="date"]::placeholder,
input[type="file"]::placeholder,
select::placeholder {
color: rgba(128, 128, 128, 0.6); }
textarea:-ms-input-placeholder,
input[type="text"]:-ms-input-placeholder,
input[type="email"]:-ms-input-placeholder,
input[type="number"]:-ms-input-placeholder,
input[type="email"]:-ms-input-placeholder,
input[type="date"]:-ms-input-placeholder,
input[type="file"]:-ms-input-placeholder,
select:-ms-input-placeholder {
color: rgba(128, 128, 128, 0.6); }
textarea::-ms-input-placeholder,
input[type="text"]::-ms-input-placeholder,
input[type="email"]::-ms-input-placeholder,
input[type="number"]::-ms-input-placeholder,
input[type="email"]::-ms-input-placeholder,
input[type="date"]::-ms-input-placeholder,
input[type="file"]::-ms-input-placeholder,
select::-ms-input-placeholder {
color: rgba(128, 128, 128, 0.6); }
input[type="number"] {
-moz-appearance: textfield; }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -98,7 +98,7 @@
// Release details
// These are automatically injected to built HTML
var build = "1538074514";
var build = "1538100775";
var version = "3.26.2";
// Construct the script tag

View File

@ -65,15 +65,22 @@ class OutputControl extends React.Component{
<div>
{
clients.map(client => {
var commands = {};
if (this.props.snapcast_client_commands[client.id]){
commands = this.props.snapcast_client_commands[client.id];
}
return (
<div className="output-control__item outputs__item--snapcast" key={client.id}>
<div className="output-control__item__name">
{client.name}
</div>
<div className="output-control__item__details">
{client.commands && client.commands.power_on ? <SnapcastPowerButton
{commands && commands.power_on ? <SnapcastPowerButton
className="output-control__item__power output-control__item__power--on"
client={client}
onClick={e => this.props.snapcastActions.sendClientCommand(client.id, commands.power_on)}
/> : null}
<VolumeControl
className="output-control__item__volume"
@ -165,9 +172,10 @@ const mapStateToProps = (state, ownProps) => {
http_streaming_enabled: state.core.http_streaming_enabled,
http_streaming_volume: state.core.http_streaming_volume,
http_streaming_mute: state.core.http_streaming_mute,
snapcast_enabled: (state.pusher.config ? state.pusher.config.snapcast_enabled : null),
pusher_connected: state.pusher.connected,
snapcast_clients: state.snapcast.clients
snapcast_enabled: (state.pusher.config ? state.pusher.config.snapcast_enabled : null),
snapcast_clients: state.snapcast.clients,
snapcast_client_commands: (state.snapcast.client_commands ? state.snapcast.client_commands : {})
}
}

View File

@ -8,7 +8,7 @@ import Icon from '../Icon'
import * as helpers from '../../helpers';
import * as snapcastActions from '../../services/snapcast/actions';
class SnapcastPowerButton extends React.Component{
export default class SnapcastPowerButton extends React.Component{
constructor(props){
super(props);
@ -17,9 +17,7 @@ class SnapcastPowerButton extends React.Component{
}
handleClick(e){
// Dynamic-ify the command itself
this.props.snapcastActions.sendClientCommand(this.props.client.id, 'power_on');
this.props.onClick(e);
}
render(){
@ -33,16 +31,4 @@ class SnapcastPowerButton extends React.Component{
</span>
);
}
}
const mapStateToProps = (state, ownProps) => {
return {}
}
const mapDispatchToProps = (dispatch) => {
return {
snapcastActions: bindActionCreators(snapcastActions, dispatch)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SnapcastPowerButton)
}

View File

@ -42,6 +42,7 @@ export default class TextField extends React.Component{
onFocus={e => this.handleFocus(e)}
onBlur={e => this.handleBlur(e)}
value={this.state.value}
placeholder={this.props.placeholder ? this.props.placeholder : null}
/>
);
}

View File

@ -87,6 +87,12 @@ class Snapcast extends React.Component{
}
if (this.state.clients_expanded.includes(client.id)){
var commands = {};
if (this.props.client_commands[client.id]){
commands = this.props.client_commands[client.id];
}
return (
<div className={class_name+" snapcast__client--expanded"} key={client.id}>
<div className="snapcast__client__header" onClick={e => this.toggleClientExpanded(client.id)}>
@ -170,9 +176,9 @@ class Snapcast extends React.Component{
</div>
<div className="input">
<TextField
onChange={value => this.props.snapcastActions.setClientCommand(client.id, "power_on", value)}
value={client.commands && client.commands.power_on ? client.commands.power_on : ""}
placeholder="Leave empty to disable"
onChange={value => this.props.snapcastActions.setClientCommand(client.id, {power_on: value})}
value={commands.power_on ? commands.power_on : ""}
placeholder="sendCommand/power_on"
/>
</div>
</div>
@ -185,9 +191,9 @@ class Snapcast extends React.Component{
</div>
<div className="input">
<TextField
onChange={value => this.props.snapcastActions.setClientCommand(client.id, "power_off", value)}
value={client.commands && client.commands.power_off ? client.commands.power_off : ""}
placeholder="Leave empty to disable"
onChange={value => this.props.snapcastActions.setClientCommand(client.id, {power_off: value})}
value={commands.power_off ? commands.power_off : ""}
placeholder="sendCommand/power_off"
/>
</div>
</div>
@ -344,7 +350,8 @@ const mapStateToProps = (state, ownProps) => {
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)
clients: (state.snapcast.clients ? state.snapcast.clients : null),
client_commands: (state.snapcast.client_commands ? state.snapcast.client_commands : {})
}
}

View File

@ -204,6 +204,15 @@ const localstorageMiddleware = (function(){
);
break;
case 'SNAPCAST_CLIENT_COMMANDS_UPDATED':
helpers.setStorage(
'snapcast',
{
client_commands: action.client_commands
}
);
break;
case 'SUPPRESS_BROADCAST':
var ui = helpers.getStorage('ui');
if (ui.suppressed_broadcasts !== undefined){

View File

@ -37,15 +37,29 @@ export function setClientLatency(id, latency){
}
}
export function setClientCommand(id, name, command){
export function setClientCommand(id, command){
return {
type: 'SNAPCAST_SET_CLIENT_COMMAND',
id: id,
name: name,
command: command
}
}
export function sendClientCommand(id, command){
return {
type: 'SNAPCAST_SEND_CLIENT_COMMAND',
id: id,
command: command
}
}
export function clientCommandsUpdated(client_commands){
return {
type: 'SNAPCAST_CLIENT_COMMANDS_UPDATED',
client_commands: client_commands
}
}
export function setClientGroup(id, group_id){
return {
type: 'SNAPCAST_SET_CLIENT_GROUP',

View File

@ -231,12 +231,37 @@ const SnapcastMiddleware = (function(){
break
case 'SNAPCAST_SET_CLIENT_COMMAND':
var client = snapcast.clients[action.id];
if (!client.commands){
client.commands = {};
}
client.commands[action.name] = action.command;
store.dispatch(snapcastActions.clientLoaded(client));
var client_commands_index = Object.assign({}, snapcast.client_commands);
if (client_commands_index[action.id]){
var client_command = Object.assign({}, client_commands_index[action.id], action.command);
} else {
var client_command = action.command;
}
client_commands_index[action.id] = client_command;
store.dispatch(snapcastActions.clientCommandsUpdated(client_commands_index));
break
case 'SNAPCAST_SEND_CLIENT_COMMAND':
store.dispatch(
pusherActions.request(
'send_broadlink_command',
{
command: action.command
},
response => {
console.log(response);
},
error => {
store.dispatch(coreActions.handleException(
'Could not send command',
error,
error.message
));
}
)
);
break
case 'SNAPCAST_SET_CLIENT_GROUP':

View File

@ -6,6 +6,19 @@ export default function reducer(snapcast = {}, action){
var server = Object.assign({}, action.server);
return Object.assign({}, snapcast, { server: server });
case 'SNAPCAST_SET_CLIENT_COMMAND':
var client_commands = snapcast.client_commands[action.id];
if (!client_commands){
client.commands = {};
}
client_commands[action.name] = action.command;
action.client_commands = client_commands;
break
case 'SNAPCAST_CLIENT_COMMANDS_UPDATED':
return Object.assign({}, snapcast, { client_commands: action.client_commands });
case 'SNAPCAST_CLIENTS_LOADED':
var clients = Object.assign({}, snapcast.clients);
for (var client of action.clients){

View File

@ -48,6 +48,18 @@ select {
background: darken($faint_grey, 3%);
}
}
&::placeholder {
color: rgba(128, 128, 128, 0.6);
}
&:-ms-input-placeholder {
color: rgba(128, 128, 128, 0.6);
}
&::-ms-input-placeholder {
color: rgba(128, 128, 128, 0.6);
}
}
input[type="number"]{