Latency limit 150; Label wrappers for text fields; Detecting image changes in playback controller

This commit is contained in:
James Barnsley
2019-02-12 20:20:25 +13:00
parent eafe6a955b
commit 2cdc1ee561
15 changed files with 3069 additions and 2372 deletions

View File

@ -6,8 +6,7 @@ import * as helpers from '../../helpers';
export default class LatencyControl extends React.Component{
constructor(props){
super(props);
super(props);
this.handleChange = helpers.throttle(this.handleChange.bind(this), 100);
}
@ -28,7 +27,7 @@ export default class LatencyControl extends React.Component{
var width = percentage;
var negative = false;
if (width > 50) width = 50;
if (width > (this.props.max / 2)) width = this.props.max / 2;
// Negative value
// We reverse it to a positive for easier maths and style rules
@ -43,7 +42,7 @@ export default class LatencyControl extends React.Component{
var negative = true;
if (left < 0) left = 0;
if (width > 50) width = 50;
if (width > (this.props.max / 2)) width = this.props.max / 2;
}
return (
@ -52,8 +51,8 @@ export default class LatencyControl extends React.Component{
<div className="slider slider--latency">
<input
type="range"
min="-100"
max="100"
min={-(this.props.max)}
max={this.props.max}
className="slider__input"
value={this.props.value}
onChange={e => this.handleChange(parseInt(e.target.value))}

View File

@ -92,15 +92,25 @@ class PlaybackControls extends React.Component{
}
}
// Started a track or changed to no track
if ((!this.props.current_track && nextProps.current_track) || (this.props.current_track && !nextProps.current_track)){
console.log("One was null, the other wasn't", {old: this.props.current_track, next: nextProps.current_track});
this.setState({current_track: nextProps.current_track});
}
// Direct swap-out of a track (with no 'null' intermediate state)
// This is precautionary and I've never been able to trigger it, but it's a good safety
if (this.props.current_track && nextProps.current_track && this.props.current_track.uri !== nextProps.current_track.uri){
console.log("URI different", {old: this.props.current_track.uri, next: nextProps.current_track.uri});
this.setState({current_track: nextProps.current_track});
}
// Images have just loaded
// A bit niggly to have to deeply check this...
if (this.props.current_track && nextProps.current_track){
if ((this.props.current_track.images && !nextProps.current_track.images) || (!this.props.current_track.images && nextProps.current_track.images)){
this.setState({current_track: nextProps.current_track});
}
}
}
handleTouchStart(e){

View File

@ -105,7 +105,7 @@ class Services extends React.Component{
return (
<div>
{not_installed}
<div className="field">
<label className="field">
<div className="name">Country</div>
<div className="input">
<input
@ -118,8 +118,8 @@ class Services extends React.Component{
An <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2" target="_blank">ISO 3166-1 alpha-2</a> country code (eg <em>NZ</em>)
</div>
</div>
</div>
<div className="field">
</label>
<label className="field">
<div className="name">Locale</div>
<div className="input">
<input
@ -132,7 +132,7 @@ class Services extends React.Component{
Lowercase <a href="http://en.wikipedia.org/wiki/ISO_639" target="_blank">ISO 639 language code</a> and an uppercase <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2" target="_blank">ISO 3166-1 alpha-2 country code</a>, joined by an underscore (eg <em>en_NZ</em>)
</div>
</div>
</div>
</label>
<div className="field current-user">
<div className="name">Current user</div>
@ -258,7 +258,7 @@ class Services extends React.Component{
</label>
</div>
</div>
<div className="field">
<label className="field">
<div className="name">Location</div>
<div className="input">
<input
@ -269,7 +269,7 @@ class Services extends React.Component{
The full URL to your stream endpoint
</div>
</div>
</div>
</label>
</div>
);
}

View File

@ -80,7 +80,7 @@ class Snapcast extends React.Component{
<div className="list snapcast__clients">
{
clients.map(client => {
var class_name = "list__item snapcast__client";
var class_name = "list__item list__item--no-interaction snapcast__client";
if (client.connected){
class_name += " snapcast__client--connected";
} else {
@ -98,7 +98,7 @@ class Snapcast extends React.Component{
</div>
</div>
<div className="snapcast__client__details">
<div className="field">
<label className="field">
<div className="name">
Name
</div>
@ -108,8 +108,8 @@ class Snapcast extends React.Component{
value={client.name}
/>
</div>
</div>
<div className="field dropdown">
</label>
<label className="field dropdown">
<div className="name">
Group
</div>
@ -129,7 +129,7 @@ class Snapcast extends React.Component{
</option>
</select>
</div>
</div>
</label>
<div className="snapcast__client__volume field">
<div className="name">
Volume
@ -153,7 +153,7 @@ class Snapcast extends React.Component{
</div>
<div className="input">
<LatencyControl
max="100"
max="150"
value={client.latency}
onChange={value => this.props.snapcastActions.setClientLatency(client.id, parseInt(value))}
/>

View File

@ -126,7 +126,7 @@ class Debug extends React.Component{
</form>
<h4 className="underline">Spotify</h4>
<div className="field">
<label className="field">
<div className="name">Access token</div>
<div className="input">
<input
@ -134,11 +134,11 @@ class Debug extends React.Component{
onChange={e => this.props.spotifyActions.authorizationGranted({access_token: e.target.value})}
value={this.state.access_token} />
</div>
</div>
</label>
<h4 className="underline">Mopidy</h4>
<form onSubmit={(e) => this.callMopidy(e)}>
<div className="field">
<label className="field">
<div className="name">Call</div>
<div className="input">
<input
@ -146,8 +146,8 @@ class Debug extends React.Component{
onChange={ e => this.setState({ mopidy_call: e.target.value })}
value={ this.state.mopidy_call } />
</div>
</div>
<div className="field">
</label>
<label className="field">
<div className="name">Data</div>
<div className="input">
<textarea
@ -155,7 +155,7 @@ class Debug extends React.Component{
value={ this.state.mopidy_data }>
</textarea>
</div>
</div>
</label>
<div className="field">
<div className="name"></div>
<div className="input">
@ -166,7 +166,7 @@ class Debug extends React.Component{
<h4 className="underline">Pusher</h4>
<form onSubmit={(e) => this.callPusher(e)}>
<div className="field">
<label className="field">
<div className="name">Examples</div>
<div className="input">
<select onChange={ e => this.setState({ pusher_data: e.target.value })}>
@ -183,8 +183,8 @@ class Debug extends React.Component{
<option value='{"method":"perform_upgrade"}'>Perform upgrade (beta)</option>
</select>
</div>
</div>
<div className="field">
</label>
<label className="field">
<div className="name">Data</div>
<div className="input">
<textarea
@ -192,7 +192,7 @@ class Debug extends React.Component{
value={ this.state.pusher_data }>
</textarea>
</div>
</div>
</label>
<div className="field">
<div className="name"></div>
<div className="input">
@ -212,13 +212,6 @@ class Debug extends React.Component{
}
}
/**
* Export our component
*
* We also integrate our global store, using connect()
**/
const mapStateToProps = (state, ownProps) => {
return {
connection_id: state.pusher.connection_id,

View File

@ -167,7 +167,7 @@ class Settings extends React.Component {
{
commands.map(command => {
return (
<div className="list__item commands-setup__item no-click" key={command.id}>
<div className="list__item commands-setup__item list__item--no-interaction" key={command.id}>
<div className="col col--w90">
<div className="commands__item commands__item--interactive" onClick={e => this.props.pusherActions.sendCommand(command.id, true)}>
<Icon className="commands__item__icon" name={command.icon} />
@ -223,7 +223,7 @@ class Settings extends React.Component {
</div>
</div>
<div className="field">
<label className="field">
<div className="name">Username</div>
<div className="input">
<input
@ -236,10 +236,10 @@ class Settings extends React.Component {
A non-unique string used to identify this client (no special characters)
</div>
</div>
</div>
</label>
<form onSubmit={(e) => this.setConfig(e)}>
<div className="field">
<label className="field">
<div className="name">Host</div>
<div className="input">
<input
@ -249,8 +249,8 @@ class Settings extends React.Component {
onBlur={e => this.setState({input_in_focus: null})}
value={ this.state.mopidy_host } />
</div>
</div>
<div className="field">
</label>
<label className="field">
<div className="name">Port</div>
<div className="input">
<input
@ -260,7 +260,7 @@ class Settings extends React.Component {
onBlur={e => this.setState({input_in_focus: null})}
value={ this.state.mopidy_port } />
</div>
</div>
</label>
{this.renderApplyButton()}
</form>
@ -393,7 +393,7 @@ class Settings extends React.Component {
</div>
</div>
<div className="field">
<label className="field">
<div className="name">Album library URI</div>
<div className="input">
<input
@ -406,7 +406,7 @@ class Settings extends React.Component {
URI used for collecting library albums
</div>
</div>
</div>
</label>
<div className="field pusher-connections">
<div className="name">Connections</div>

View File

@ -16,10 +16,6 @@
padding: 0 20px;
border-radius: 3px;
&:not(.no-click){
cursor: pointer;
}
&:before {
pointer-events: none;
content: '';
@ -42,7 +38,9 @@
}
}
:root .notouch:not(.dragging) &:not(.no-click) {
:root .notouch:not(.dragging) &:not(.list__item--no-interaction){
cursor: pointer;
&:hover {
cursor: pointer;
background: rgba(255,255,255,0.03);
@ -57,7 +55,7 @@
}
}
:root .light-theme.notouch:not(.dragging) &:not(.no-click) {
:root .light-theme.notouch:not(.dragging) &:not(.no-click) &:not(.list__item--no-interaction) {
&:hover {
background: rgba(0,0,0,0.03);
}

View File

@ -429,10 +429,6 @@ select {
}
}
label {
display: inline-block;
}
.label {
.tooltip {
left: -4px;