Skip to content

Commit

Permalink
feat: add channel settings UI
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarpl committed Jun 12, 2019
1 parent c3e395c commit 8351cb0
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 4 deletions.
3 changes: 3 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
MIT License

Producers Audio Mixer: Copyright (c) TV2 Denmark
Contributions: Copyright (c) 2019 Norsk rikskringkasting AS
Boilerplate: Copyright (c) Alex Devero <[email protected]> (alexdevero.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
Expand All @@ -20,3 +21,5 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Cogwheel icon by Freepik from www.flaticon.com is licensed by CC 3.0 BY
24 changes: 24 additions & 0 deletions src/assets/css/Channel.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
margin: 4px;
border-radius: 10px;
max-width: 100px;
position: relative;
}


Expand Down Expand Up @@ -180,6 +181,29 @@ input[type=range]:focus::-webkit-slider-runnable-track {
background: #000000;
}

.channel-settings {
position: absolute;
top: 5px;
left: 9px;
background: none;
border: none;
outline: none;
}

.channel-settings:hover > svg {
fill: rgba(255, 255, 255, 0.5);
}

.channel-settings:active > svg {
fill: rgba(255, 255, 255, 1);
}

.channel-settings > svg {
width: 25px;
height: 25px;
fill: rgba(255, 255, 255, 0.3);
}

.channel-body.with-snaps .vumeter-body {
height: 230px;
}
62 changes: 62 additions & 0 deletions src/assets/css/ChannelSettings.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
.channel-settings-body {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
overflow: auto;
max-height: 90vh;
background-color: rgb(31, 31, 31);
border-color: rgb(124, 124, 124);
border-style: solid;
border-width: 4px;
text-align: center;
z-index: 1;

color: #fff;
}

.channel-settings-body > h2 {
border-bottom: 1px solid #999;
margin: 0;
padding: 10px 0;
line-height: 50px;
}

.channel-settings-body > .close {
position: absolute;
outline : none;
border-color: rgb(99, 99, 99);
background-color: rgb(27, 27, 27);
border-radius: 100%;
display: block;
color: #fff;
width: 50px;
height: 50px;
font-size: 30px;
line-height: 50px;
top: 9px;
right: 9px;
}

.channel-settings-group {
border-bottom: 1px solid #999;
}

.channel-settings-group > button {
line-height: 10px;

outline : none;
border-color: rgb(99, 99, 99);
background-color: rgb(27, 27, 27);
margin-right: auto;
margin-top: 15px;
margin-bottom: 15px;
margin-left: auto;
border-radius: 7px;
display: block;
color: #fff;
width: 90%;
font-size: 30px;
line-height: 50px;
}
35 changes: 34 additions & 1 deletion src/components/Channel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Store } from 'redux';

//assets:
import '../assets/css/Channel.css';
import { IMixerProtocol, MixerProtocolPresets, IMixerProtocolGeneric } from '../constants/MixerProtocolPresets';
import { IMixerProtocol, MixerProtocolPresets, IMixerProtocolGeneric, ICasparCGMixerGeometry } from '../constants/MixerProtocolPresets';
import { any } from 'prop-types';

interface IChannelInjectProps {
Expand Down Expand Up @@ -95,6 +95,13 @@ class Channel extends React.Component<IChannelProps & IChannelInjectProps & Stor
});
}

handleShowOptions() {
this.props.dispatch({
type: 'TOGGLE_SHOW_OPTION',
channel: this.channelIndex
});
}

fader() {
return (
<input className="channel-volume-slider"
Expand Down Expand Up @@ -175,6 +182,31 @@ class Channel extends React.Component<IChannelProps & IChannelInjectProps & Stor
}
}

channelSettings = () => {
const mixerProtocol = this.mixerProtocol as ICasparCGMixerGeometry
if (mixerProtocol.sourceOptions) {
return <React.Fragment>
<button className="channel-settings" onClick={e => this.handleShowOptions()}>
<svg version="1.1" id="cogwheel" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 340.274 340.274">
<g>
<path d="M293.629,127.806l-5.795-13.739c19.846-44.856,18.53-46.189,14.676-50.08l-25.353-24.77l-2.516-2.12h-2.937
c-1.549,0-6.173,0-44.712,17.48l-14.184-5.719c-18.332-45.444-20.212-45.444-25.58-45.444h-35.765
c-5.362,0-7.446-0.006-24.448,45.606l-14.123,5.734C86.848,43.757,71.574,38.19,67.452,38.19l-3.381,0.105L36.801,65.032
c-4.138,3.891-5.582,5.263,15.402,49.425l-5.774,13.691C0,146.097,0,147.838,0,153.33v35.068c0,5.501,0,7.44,46.585,24.127
l5.773,13.667c-19.843,44.832-18.51,46.178-14.655,50.032l25.353,24.8l2.522,2.168h2.951c1.525,0,6.092,0,44.685-17.516
l14.159,5.758c18.335,45.438,20.218,45.427,25.598,45.427h35.771c5.47,0,7.41,0,24.463-45.589l14.195-5.74
c26.014,11,41.253,16.585,45.349,16.585l3.404-0.096l27.479-26.901c3.909-3.945,5.278-5.309-15.589-49.288l5.734-13.702
c46.496-17.967,46.496-19.853,46.496-25.221v-35.029C340.268,146.361,340.268,144.434,293.629,127.806z M170.128,228.474
c-32.798,0-59.504-26.187-59.504-58.364c0-32.153,26.707-58.315,59.504-58.315c32.78,0,59.43,26.168,59.43,58.315
C229.552,202.287,202.902,228.474,170.128,228.474z"/>
</g>
</svg>
</button>
</React.Fragment>
}
return null
}

render() {
return (
this.props.showChannel === false ?
Expand All @@ -184,6 +216,7 @@ class Channel extends React.Component<IChannelProps & IChannelInjectProps & Stor
"with-snaps": this.props.showSnaps,
"with-pfl": this.props.showPfl
})}>
{this.channelSettings()}
{this.fader()}
<VuMeter channelIndex = {this.channelIndex}/>
<br/>
Expand Down
76 changes: 76 additions & 0 deletions src/components/ChannelSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import React from 'react';

import '../assets/css/ChannelSettings.css';
import { IMixerProtocolGeneric, MixerProtocolPresets, ICasparCGMixerGeometry } from '../constants/MixerProtocolPresets';
import { Store } from 'redux';
import { connect } from 'react-redux';

interface IChannelSettingsInjectProps {
label: string,
mixerProtocol: string,
}

interface IChannelProps {
channelIndex: number
}

class ChannelSettings extends React.PureComponent<IChannelProps & IChannelSettingsInjectProps & Store> {
mixerProtocol: ICasparCGMixerGeometry | undefined;
channelIndex: number;

constructor(props: any) {
super(props);
this.channelIndex = this.props.channelIndex;
const protocol = MixerProtocolPresets[this.props.mixerProtocol] as ICasparCGMixerGeometry;
if (protocol.sourceOptions) {
this.mixerProtocol = protocol;
}
}

handleOption = (prop: string, option: string) => {
this.props.dispatch({
type: 'SET_OPTION',
channel: this.channelIndex,
prop,
option
});
}

handleClose = () => {
this.props.dispatch({
type: 'TOGGLE_SHOW_OPTION',
channel: this.channelIndex
});
}

render() {
return (
<div className="channel-settings-body">
<h2>{this.props.label || ("CH " + (this.channelIndex + 1))}</h2>
<button className="close" onClick={() => this.handleClose()}>X</button>
{this.mixerProtocol &&
this.mixerProtocol.sourceOptions &&
Object.getOwnPropertyNames(this.mixerProtocol.sourceOptions.options).map(prop => {
return (
<div className="channel-settings-group" key={prop}>
{Object.getOwnPropertyNames(this.mixerProtocol!.sourceOptions!.options[prop]).map(option => {
console.log(prop, option)
return <button key={option} className="channel-settings-group-item" onClick={() => this.handleOption(prop, this.mixerProtocol!.sourceOptions!.options[prop][option])}>{option}</button>
}) || null}
</div>
)
})}
</div>
)
}
}

const mapStateToProps = (state: any, props: any): IChannelSettingsInjectProps => {
console.log(state.channels[0].channel, props.channelIndex);
return {
label: state.channels[0].channel[props.channelIndex].label,
mixerProtocol: state.settings[0].mixerProtocol
}
}

export default connect<any, IChannelSettingsInjectProps>(mapStateToProps)(ChannelSettings) as any;
2 changes: 2 additions & 0 deletions src/components/Channels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import GrpFader from './GrpFader';
import '../assets/css/Channels.css';
import { Store } from 'redux';
import { IAppProps } from './App';
import ChannelSettings from './ChannelSettings';

class Channels extends PureComponent<IAppProps & Store> {
constructor(props: any) {
Expand Down Expand Up @@ -64,6 +65,7 @@ class Channels extends PureComponent<IAppProps & Store> {
render() {
return (
<div className="channels-body">
{(typeof this.props.store.settings[0].showOptions === "number") && <ChannelSettings channelIndex={this.props.store.settings[0].showOptions} />}
{this.props.store.channels[0].channel.map((none: any, index: number) => {
return <Channel
channelIndex = {index}
Expand Down
24 changes: 23 additions & 1 deletion src/constants/MixerProtocolPresets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ export interface ICasparCGMixerGeometryFile {
PGM_CHANNEL_FADER_LEVEL: Array<ChannelLayerPair[]>,
MONITOR_CHANNEL_FADER_LEVEL: Array<ChannelLayerPair[]>
}
sourceOptions?: {
sources: (ChannelLayerPair & {
producer: string,
file: string
})
options: {
[key: string]: { // producer property invocation
[key: string]: string // label: property
}
}
}
}

export interface ICasparCGMixerGeometry extends IMixerProtocolGeneric {
Expand All @@ -81,7 +92,18 @@ export interface ICasparCGMixerGeometry extends IMixerProtocolGeneric {
PGM_CHANNEL_FADER_LEVEL: Array<ChannelLayerPair[]>,
MONITOR_CHANNEL_FADER_LEVEL: Array<ChannelLayerPair[]>,
}
channelLabels?: string[]
channelLabels?: string[],
sourceOptions?: {
sources: (ChannelLayerPair & {
producer: string,
file: string
})
options: {
[key: string]: { // producer property invocation
[key: string]: string // label: property
}
}
}
}

interface IMessageProtocol {
Expand Down
3 changes: 2 additions & 1 deletion src/constants/mixerProtocols/casparCGMaster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ if (geometry) {
zero: 0.75,
test: 0.6,
},
channelLabels: geometry.channelLabels
channelLabels: geometry.channelLabels,
sourceOptions: geometry.sourceOptions
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/reducers/channelsReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface IChannel {
pstOn: boolean,
pflOn: boolean,
showChannel: boolean,
snapOn: Array<boolean>,
snapOn: Array<boolean>
}

interface IVuMeters {
Expand Down
5 changes: 5 additions & 0 deletions src/reducers/settingsReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { MixerProtocolPresets } from '../constants/MixerProtocolPresets';
export interface ISettings {
showSnaps: boolean,
showSettings: boolean,
showOptions: number | false,
mixerProtocol: string,
localIp: string,
localOscPort: number,
Expand All @@ -23,6 +24,7 @@ const defaultSettingsReducerState: Array<ISettings> = [
{
showSnaps: false,
showSettings: false,
showOptions: false,
mixerProtocol: "genericMidi",
localIp: "0.0.0.0",
localOscPort: 8000,
Expand All @@ -45,6 +47,9 @@ export const settings = (state = defaultSettingsReducerState, action: any): Arra
case 'TOGGLE_SHOW_SETTINGS':
nextState[0].showSettings = !nextState[0].showSettings;
return nextState;
case 'TOGGLE_SHOW_OPTION':
nextState[0].showOptions = typeof nextState[0].showOptions === "number" ? false : action.channel;
return nextState;
case 'TOGGLE_SHOW_SNAPS':
nextState[0].showSnaps = !nextState[0].showSnaps;
return nextState;
Expand Down

0 comments on commit 8351cb0

Please sign in to comment.