diff --git a/src/js/components/ContextMenu/ContextMenuItems.js b/src/js/components/ContextMenu/ContextMenuItems.js index 94d98234..cc141c49 100644 --- a/src/js/components/ContextMenu/ContextMenuItems.js +++ b/src/js/components/ContextMenu/ContextMenuItems.js @@ -8,8 +8,7 @@ import Icon from '../Icon'; import { loadAlbum, loadArtist, - loadTrack, - loadTracks, + loadPlaylist, removeTracksFromPlaylist, deletePlaylist, } from '../../services/core/actions'; @@ -129,7 +128,7 @@ const ContextMenuItems = ({ )} - + ); diff --git a/src/js/components/Fields/LatencyControl.js b/src/js/components/Fields/LatencyControl.js index 2fc901ed..7077af47 100755 --- a/src/js/components/Fields/LatencyControl.js +++ b/src/js/components/Fields/LatencyControl.js @@ -1,65 +1,70 @@ import React from 'react'; +import TextField from './TextField'; import { throttle } from '../../util/helpers'; -export default class LatencyControl extends React.Component { - constructor(props) { - super(props); - this.handleChange = throttle(this.handleChange.bind(this), 100); - } +const LatencyControl = ({ + onChange, + value: valueProp, + max, +}) => { + let value = valueProp; + const throttledChange = (nextValue) => onChange(nextValue, value); + const handleChange = throttle(throttledChange, 100); + let percentage = Math.round((value / max) * 100 / 2); + let left = 50; + let width = percentage; + let negative = false; - handleChange(value) { - this.props.onChange(value, this.props.value); - } - - render() { - // Zero, or positive value - if (this.props.value >= 0) { - var { value } = this.props; - if (value > this.props.max) { - value = this.props.max; - } - var percentage = Math.round((value / this.props.max) * 100 / 2); - var left = 50; - var width = percentage; - var negative = false; - - 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 - } else { - var value = -this.props.value; - if (value < -this.props.max) { - value = -this.props.max; - } - var percentage = Math.round((value / this.props.max) * 100 / 2); - var left = 50 - percentage; - var width = percentage; - var negative = true; - - if (left < 0) left = 0; - if (width > (this.props.max / 2)) width = this.props.max / 2; + // Zero, or positive value + if (value >= 0) { + if (value > max) { + value = max; } + if (width > (max / 2)) width = max / 2; - return ( - -
-
- this.handleChange(parseInt(e.target.value))} - /> -
-
-
-
+ // Negative value + // We reverse it to a positive for easier maths and style rules + } else { + value = -value; + if (value < -max) { + value = -max; + } + percentage = Math.round((value / max) * 100 / 2); + left = 50 - percentage; + width = percentage; + negative = true; + + if (left < 0) left = 0; + if (width > (max / 2)) width = max / 2; + } + + return ( + +
+
+ handleChange(parseInt(e.target.value, 10))} + /> +
+
+
- - ); - } +
+ + + ); } + +export default LatencyControl; diff --git a/src/js/components/Link.js b/src/js/components/Link.js index f10c29a9..e495eb3d 100755 --- a/src/js/components/Link.js +++ b/src/js/components/Link.js @@ -40,6 +40,7 @@ const Link = ({ retainScroll, scrollTo: scrollTarget, onContextMenu, + onClick, className = '', activeClassName, to, @@ -49,9 +50,12 @@ const Link = ({ if (!to) return {children}; const history = useHistory(); const location = useLocation(); - const onClick = () => updateScrollPosition({ - history, location, retainScroll, scrollTarget, - }); + const handleClick = (e) => { + updateScrollPosition({ + history, location, retainScroll, scrollTarget, + }); + if (onClick) onClick(e); + } // Decode both links. This handles issues where one link is encoded and the other isn't, but // they're otherwise identical @@ -63,7 +67,7 @@ const Link = ({ const active = history && isLinkActive ? (activeClassName || 'active') : ''; return ( { if (!clients || clients.length <= 0) { return ( @@ -77,15 +78,18 @@ const SnapcastClients = ({ value={client.latency} onChange={(value) => actions.setClientLatency(client.id, parseInt(value))} /> - actions.setClientLatency(client.id, parseInt(value))} - value={String(client.latency)} - autosave - />
+
+ actions.deleteClient(client.id)} + to="/settings/services/snapcast/" + scrollTo="#services-menu" + > + + +
{ const renderMenuItem = (simpleGroup) => { const group = collate(simpleGroup, { clients }); - const anyClients = ( - !show_disconnected_clients && ( - !group.clients - || !group.clients.length - || !group.clients.filter((client) => client.connected).length - ) + const noClients = ( + !group.clients + || !group.clients.length + || !group.clients.filter((client) => client.connected).length ); + + if (noClients && !show_disconnected_clients) return null; + return ( { - store.dispatch({ - type: 'SNAPCAST_CLIENT_REMOVED', - key: action.data.params.id, - }); + (response) => { + // Groups contain clients + store.dispatch(snapcastActions.groupsLoaded(response.server.groups, true)); }, (error) => { store.dispatch(coreActions.handleException( diff --git a/src/js/services/snapcast/reducer.js b/src/js/services/snapcast/reducer.js index 88618893..bde973f1 100755 --- a/src/js/services/snapcast/reducer.js +++ b/src/js/services/snapcast/reducer.js @@ -18,6 +18,12 @@ export default function reducer(snapcast = {}, action) { case 'SNAPCAST_CLIENTS_LOADED': return { ...snapcast, clients: action.clients }; + case 'SNAPCAST_CLIENT_DELETED': { + const clients = { ...snapcast.clients }; + delete clients[action.key]; + return { ...snapcast, clients }; + } + case 'SNAPCAST_GROUPS_LOADED': if (action.flush) { var groups = {}; diff --git a/src/scss/components/_snapcast.scss b/src/scss/components/_snapcast.scss index 352e1280..06371f73 100755 --- a/src/scss/components/_snapcast.scss +++ b/src/scss/components/_snapcast.scss @@ -129,7 +129,7 @@ &__client { @include clearfix(); - padding: 10px 10px 10px 60px; + padding: 10px 10px 30px 60px; position: relative; margin: 0; width: 25%; @@ -178,16 +178,14 @@ &__latency { input[type="number"] { - width: 20%; + max-width: 70px; } .latency-control { - display: inline-block; - vertical-align: middle; - padding-top: 4px; - width: 80%; - padding-right: 10px; - box-sizing: border-box; + display: flex; + flex-flow: row; + align-items: center; + gap: 10px; .zero { position: absolute;