Skip to content

Commit

Permalink
Relocating stream checkbox to Outputs panel
Browse files Browse the repository at this point in the history
- Making it easier to switch current device streaming on/off
- Refactor `Stream` to functional component
  • Loading branch information
jaedb committed Aug 11, 2023
1 parent 45cd06b commit 41fcfa9
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 96 deletions.
47 changes: 38 additions & 9 deletions src/js/components/Fields/OutputControl.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ import Thumbnail from '../Thumbnail';
import LinksSentence from '../LinksSentence';
import DropdownField from './DropdownField';
import * as pusherActions from '../../services/pusher/actions';
import * as snapcastActions from '../../services/snapcast/actions';
import {
setGroupStream,
setClientMute,
setClientVolume,
setStreamingEnabled,
controlStream,
} from '../../services/snapcast/actions';
import { sortItems, indexToArray } from '../../util/arrays';
import { titleCase } from '../../util/helpers';
import { I18n, i18n } from '../../locale';
Expand Down Expand Up @@ -38,10 +44,10 @@ const Header = ({
let onClick = null;
switch (playbackStatus) {
case 'playing':
if (canPause) onClick = () => dispatch(snapcastActions.controlStream(id, 'pause'));
if (canPause) onClick = () => dispatch(controlStream(id, 'pause'));
break;
default:
if (canPlay) onClick = () => dispatch(snapcastActions.controlStream(id, 'play'));
if (canPlay) onClick = () => dispatch(controlStream(id, 'play'));
break;
}

Expand Down Expand Up @@ -88,6 +94,7 @@ const Header = ({
};

const Group = ({
setExpanded,
group: {
id: groupId,
name: groupName,
Expand All @@ -111,6 +118,7 @@ const Group = ({
className="text"
to={`/settings/services/snapcast/${groupId}`}
scrollTo="#services-snapcast-groups"
onClick={() => setExpanded(false)}
>
{titleCase(groupName)}
</Link>
Expand All @@ -121,7 +129,7 @@ const Group = ({
options={allStreams.map((s) => ({ value: s.id, label: titleCase(s.id) }))}
noLabel
handleChange={
(value) => dispatch(snapcastActions.setGroupStream(groupId, value))
(value) => dispatch(setGroupStream(groupId, value))
}
/>
</h5>
Expand All @@ -143,14 +151,14 @@ const Group = ({
noTooltip
mute={mute}
onMuteChange={
(value) => dispatch(snapcastActions.setClientMute(clientId, value))
(value) => dispatch(setClientMute(clientId, value))
}
/>
<VolumeControl
volume={volume}
mute={mute}
onVolumeChange={
(value) => dispatch(snapcastActions.setClientVolume(clientId, value))
(value) => dispatch(setClientVolume(clientId, value))
}
/>
</div>
Expand All @@ -162,11 +170,13 @@ const Group = ({
);
};

const Outputs = () => {
const Outputs = ({ setExpanded }) => {
const dispatch = useDispatch();
const allGroups = indexToArray(useSelector((state) => state.snapcast.groups || {}));
const allStreams = useSelector((state) => state.snapcast.streams || {});
const allServers = indexToArray(useSelector((state) => state.mopidy.servers || {}));
const groupsByStream = groupBy(allGroups, 'stream_id');
const { streaming_enabled } = useSelector((state) => state?.snapcast || {});

return (
<ErrorBoundary>
Expand All @@ -180,10 +190,29 @@ const Outputs = () => {
return (
<div className="output-control__stream" key={`stream_${id}`}>
<Header stream={stream} />
{groups.map((group) => <Group group={group} key={`group_${group.id}`} />)}
{
groups.map(
(group) => (
<Group setExpanded={setExpanded} group={group} key={`group_${group.id}`} />
)
)
}
</div>
);
})}
<div className="field checkbox" style={{ paddingLeft: 12 }}>
<label>
<input
type="checkbox"
name="streaming_enabled"
checked={streaming_enabled}
onChange={() => dispatch(setStreamingEnabled(!streaming_enabled))}
/>
<span className="label">
<I18n path="snapcast.stream_on_this_device" />
</span>
</label>
</div>
</ErrorBoundary>
);
}
Expand Down Expand Up @@ -241,7 +270,7 @@ const OutputControl = ({ force_expanded }) => {
</button>
<div className="output-control__inner">
{!isEmpty(commands) && <Commands commands={commands} />}
{snapcastEnabled && <Outputs />}
{snapcastEnabled && <Outputs setExpanded={setExpanded} />}
</div>
</span>
);
Expand Down
12 changes: 0 additions & 12 deletions src/js/components/Snapcast.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,6 @@ const Snapcast = (props) => {
<I18n path="snapcast.enabled" />
</span>
</label>
<label>
<input
type="checkbox"
name="streaming_enabled"
checked={streaming_enabled}
disabled={!enabled}
onChange={() => actions.setStreamingEnabled(!streaming_enabled)}
/>
<span className="label">
<I18n path="snapcast.streaming_enabled" />
</span>
</label>
<label>
<input
type="checkbox"
Expand Down
104 changes: 31 additions & 73 deletions src/js/components/Stream.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,43 @@
import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as coreActions from '../services/core/actions';
import { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { SnapStream } from './SnapStream.tsx';

class Stream extends React.Component {
constructor(props) {
super(props);

if (props.enabled && props.streaming_enabled) {
this.start();
}
}

start = () => {
const {
host,
port,
ssl,
} = this.props;
const Stream = () => {
const [stream, setStream] = useState(null);
const {
enabled,
streaming_enabled,
host,
port,
ssl,
} = useSelector((state) => state?.snapcast || {});

if (this.snapstream) {
this.snapstream.play();
const start = () => {
if (stream) {
stream.play();
} else {
const baseUrl = `${ssl ? 'wss' : 'ws'}://${host}:${port}`;
this.snapstream = new SnapStream(baseUrl);
}
}

stop = () => {
if (this.snapstream) {
this.snapstream.stop();
this.snapstream = null;
setStream(new SnapStream(`${ssl ? 'wss' : 'ws'}://${host}:${port}`));
}
}

componentDidUpdate = ({
streaming_enabled: prevStreamingEnabled,
}) => {
const {
enabled,
streaming_enabled,
} = this.props;

if (!prevStreamingEnabled && enabled && streaming_enabled) {
this.start();
}
if (!enabled || !streaming_enabled) {
this.stop();
const stop = () => {
if (stream) {
stream.stop();
setStream(null);
}
}

render = () => null;
useEffect(
() => {
if (enabled && streaming_enabled) {
start();
} else {
stop();
}
}, [enabled, streaming_enabled],
);

return null;
}

const mapStateToProps = (state) => {
const {
snapcast: {
enabled,
streaming_enabled,
host,
port,
ssl,
},
pusher: {
username,
},
} = state;

return {
enabled,
streaming_enabled,
host,
port,
ssl,
username,
};
};

const mapDispatchToProps = (dispatch) => ({
coreActions: bindActionCreators(coreActions, dispatch),
});

export default connect(mapStateToProps, mapDispatchToProps)(Stream);
export default Stream;
1 change: 1 addition & 0 deletions src/js/locale/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ playback_controls:
snapcast:
enabled: Enabled
streaming_enabled: Streaming enabled
stream_on_this_device: Stream on this device
show_disconnected_clients: Show disconnected clients
no_connected_clients: No connected clients
host: Host
Expand Down
4 changes: 2 additions & 2 deletions src/js/views/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ class Settings extends React.Component {
<I18n path="settings.services.title" />
<a name="services" />
</h4>

<Services />

<h4 className="underline">
Expand Down Expand Up @@ -456,7 +456,7 @@ class Settings extends React.Component {
<a
target="_blank"
rel="noopener noreferrer"
className="flag flag--dark"
className="flag flag--dark flag--inline"
href={`https://github.com/jaedb/Iris/releases/tag/${pusher.version.latest}`}
>
<Icon name="cloud_download" className="blue-text" />
Expand Down
4 changes: 4 additions & 0 deletions src/scss/global/_core.scss
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,10 @@ footer {
font-size: 12px;
}

&--inline {
vertical-align: middle;
}

h1 &,
h2 & {
line-height: 1.4em;
Expand Down

0 comments on commit 41fcfa9

Please sign in to comment.