diff --git a/client/components/Channels.tsx b/client/components/Channels.tsx index dc902999..cdded8a5 100644 --- a/client/components/Channels.tsx +++ b/client/components/Channels.tsx @@ -9,13 +9,14 @@ import { Store } from 'redux' import { TOGGLE_SHOW_SETTINGS, TOGGLE_SHOW_STORAGE, + SET_PAGE, } from '../../server/reducers/settingsActions' import ChannelRouteSettings from './ChannelRouteSettings' import ChanStrip from './ChanStrip' import ChannelMonitorOptions from './ChannelMonitorOptions' import { IChannels } from '../../server/reducers/channelsReducer' import { IFader } from '../../server/reducers/fadersReducer' -import { ISettings } from '../../server/reducers/settingsReducer' +import { ISettings, PageType } from '../../server/reducers/settingsReducer' import { SOCKET_NEXT_MIX, SOCKET_CLEAR_PST, @@ -44,7 +45,10 @@ class Channels extends React.Component { nextProps.settings.showMonitorOptions || this.props.settings.mixerOnline !== nextProps.settings.mixerOnline || - this.props.faders.length !== nextProps.faders.length + this.props.faders.length !== nextProps.faders.length || + this.props.settings.currentPage !== + nextProps.settings.currentPage || + this.props.settings.pageLength !== nextProps.settings.pageLength ) } @@ -74,6 +78,113 @@ class Channels extends React.Component { }) } + handlePages(type: PageType, i: number | string) { + if (typeof i === 'string') { + this.props.dispatch({ + type: SET_PAGE, + pageType: type, + id: i, + }) + } else { + this.props.dispatch({ + type: SET_PAGE, + pageType: type, + start: i * this.props.settings.pageLength, + }) + } + } + + renderPageButtons() { + if (this.props.settings.enablePages === false) { + return undefined + } + + const customPageButtons = [] + const pages = window.customPagesList + if (pages) { + for (const p of pages) { + customPageButtons.push( + + ) + } + } + + const numberedButtons = [] + const numberOfFaders = this.props.settings.numberOfFaders + const pageLength = this.props.settings.pageLength + for (let i = 0; i < Math.ceil(numberOfFaders / pageLength); i++) { + numberedButtons.push( + + ) + } + + return ( + + {customPageButtons} + {numberedButtons} + + + ) + } + + renderFaders() { + const curPage = this.props.settings.currentPage + const pageLength = this.props.settings.pageLength + switch (curPage.type) { + case PageType.All: + return this.props.faders.map((value, index) => ( + + )) + case PageType.NumberedPage: + return this.props.faders + .slice( + curPage.start, + Number(curPage.start!) + Number(pageLength) + ) + .map((value, index) => ( + + )) + case PageType.CustomPage: + const page = window.customPagesList.find( + (page) => page.id === curPage.id + ) + if (!page) return + + return this.props.faders + .filter((v, i) => page.faders.find((f) => i === f)) + .map((value, index) => ( + + )) + } + } + render() { return (
@@ -100,9 +211,7 @@ class Channels extends React.Component { faderIndex={this.props.settings.showMonitorOptions} /> ) : null} - {this.props.faders.map((none: any, index: number) => { - return - })} + {this.renderFaders()}
{this.props.settings.mixerOnline ? ( @@ -176,6 +285,8 @@ class Channels extends React.Component { }
+ + {this.renderPageButtons()}
) diff --git a/client/components/Settings.tsx b/client/components/Settings.tsx index ef384de9..ef1074d0 100644 --- a/client/components/Settings.tsx +++ b/client/components/Settings.tsx @@ -374,6 +374,16 @@ class Settings extends React.PureComponent { />
+ +

+ +
{window.mixerProtocol.protocol === 'MIDI' ? this.renderMixerMidiSettings() : ''} diff --git a/client/index.tsx b/client/index.tsx index 6fd37686..7ff20215 100644 --- a/client/index.tsx +++ b/client/index.tsx @@ -12,6 +12,7 @@ import { SOCKET_GET_SNAPSHOT_LIST, SOCKET_GET_CCG_LIST, SOCKET_GET_MIXER_PRESET_LIST, + SOCKET_GET_PAGES_LIST, } from '../server/constants/SOCKET_IO_DISPATCHERS' import { I18nextProvider } from 'react-i18next' @@ -28,6 +29,11 @@ declare global { snapshotFileList: string[] ccgFileList: string[] mixerPresetList: string[] + customPagesList: Array<{ + id: string + label: string + faders: Array + }> } } @@ -40,6 +46,7 @@ window.socketIoClient = io() window.socketIoClient.emit(SOCKET_GET_SNAPSHOT_LIST) window.socketIoClient.emit(SOCKET_GET_CCG_LIST) window.socketIoClient.emit(SOCKET_GET_MIXER_PRESET_LIST) +window.socketIoClient.emit(SOCKET_GET_PAGES_LIST) console.log('Setting up SocketIO connection') socketClientHandlers() diff --git a/client/utils/SocketClientHandlers.ts b/client/utils/SocketClientHandlers.ts index 6ad6c65a..7c15b0f2 100644 --- a/client/utils/SocketClientHandlers.ts +++ b/client/utils/SocketClientHandlers.ts @@ -24,6 +24,7 @@ import { SOCKET_SET_MIXER_ONLINE, SOCKET_SET_ALL_VU, SOCKET_RETURN_MIXER_PRESET_LIST, + SOCKET_RETURN_PAGES_LIST, } from '../../server/constants/SOCKET_IO_DISPATCHERS' export const socketClientHandlers = () => { @@ -148,4 +149,7 @@ export const socketClientHandlers = () => { .on(SOCKET_RETURN_MIXER_PRESET_LIST, (payload: any) => { window.mixerPresetList = payload }) + .on(SOCKET_RETURN_PAGES_LIST, (payload: any) => { + window.customPagesList = payload + }) } diff --git a/server/MainThreadHandler.ts b/server/MainThreadHandler.ts index 4b922963..4be10d33 100644 --- a/server/MainThreadHandler.ts +++ b/server/MainThreadHandler.ts @@ -8,7 +8,7 @@ import { import { SnapshotHandler } from './utils/SnapshotHandler' import { socketServer } from './expressHandler' -import { UPDATE_SETTINGS } from './reducers/settingsActions' +import { UPDATE_SETTINGS, LOAD_CUSTOM_PAGES } from './reducers/settingsActions' import { loadSettings, saveSettings, @@ -16,6 +16,7 @@ import { getCcgSettingsList, setCcgDefault, getMixerPresetList, + getCustomPages, } from './utils/SettingsStorage' import { SOCKET_TOGGLE_PGM, @@ -56,6 +57,8 @@ import { SOCKET_RETURN_MIXER_PRESET_LIST, SOCKET_LOAD_MIXER_PRESET, SOCKET_SET_INPUT_SELECTOR, + SOCKET_GET_PAGES_LIST, + SOCKET_RETURN_PAGES_LIST, } from './constants/SOCKET_IO_DISPATCHERS' import { TOGGLE_PGM, @@ -192,6 +195,10 @@ export class MainThreadHandlers { mixerGenericConnection.loadMixerPreset(payload) this.updateFullClientStore() }) + .on(SOCKET_GET_PAGES_LIST, () => { + logger.info('Get custom pages list', {}) + socketServer.emit(SOCKET_RETURN_PAGES_LIST, getCustomPages()) + }) .on(SOCKET_SAVE_SETTINGS, (payload: any) => { logger.info('Save settings :' + String(payload), {}) saveSettings(payload) diff --git a/server/constants/SOCKET_IO_DISPATCHERS.ts b/server/constants/SOCKET_IO_DISPATCHERS.ts index 497976e6..911f8421 100644 --- a/server/constants/SOCKET_IO_DISPATCHERS.ts +++ b/server/constants/SOCKET_IO_DISPATCHERS.ts @@ -41,6 +41,8 @@ export const SOCKET_LOAD_MIXER_PRESET = 'loadMixerPreset' export const SOCKET_LOAD_SNAPSHOT = 'loadSnapshot' export const SOCKET_SAVE_SNAPSHOT = 'saveSnapshot' export const SOCKET_SAVE_CCG_FILE = 'saveCcgFile' +export const SOCKET_GET_PAGES_LIST = 'getPagesList' +export const SOCKET_RETURN_PAGES_LIST = 'getPagesList' // Store updates: export const SOCKET_SET_FULL_STORE = 'setFullStore' diff --git a/server/reducers/settingsActions.ts b/server/reducers/settingsActions.ts index 386fd8fa..01c41679 100644 --- a/server/reducers/settingsActions.ts +++ b/server/reducers/settingsActions.ts @@ -7,3 +7,4 @@ export const TOGGLE_SHOW_SNAPS = 'TOGGLE_SHOW_SNAPS' export const UPDATE_SETTINGS = 'UPDATE_SETTINGS' export const SET_MIXER_ONLINE = 'SET_MIXER_ONLINE' export const SET_SERVER_ONLINE = 'SET_SERVER_ONLINE' +export const SET_PAGE = 'SET_PAGE' diff --git a/server/reducers/settingsReducer.ts b/server/reducers/settingsReducer.ts index 3dfd0cf7..f7d88b92 100644 --- a/server/reducers/settingsReducer.ts +++ b/server/reducers/settingsReducer.ts @@ -10,15 +10,35 @@ import { SET_MIXER_ONLINE, TOGGLE_SHOW_MONITOR_OPTIONS, SET_SERVER_ONLINE, + SET_PAGE, } from '../reducers/settingsActions' +export enum PageType { + All, + NumberedPage, + CustomPage, +} + export interface ISettings { + /** UI state (non persistant) */ showSnaps: boolean showSettings: boolean showChanStrip: number showOptions: number | false showMonitorOptions: number showStorage: boolean + currentPage: { + type: PageType + start?: number + id?: string + } + customPages?: Array<{ + id: string + label: string + faders: Array + }> + + /** User config */ mixerProtocol: string localIp: string localOscPort: number @@ -42,6 +62,10 @@ export interface ISettings { automationMode: boolean offtubeMode: boolean showPfl: boolean + enablePages: boolean + pageLength: number + + /** Connection state */ mixerOnline: boolean serverOnline: boolean } @@ -54,6 +78,8 @@ const defaultSettingsReducerState: Array = [ showOptions: false, showMonitorOptions: -1, showStorage: false, + currentPage: { type: PageType.All }, + mixerProtocol: 'sslSystemT', localIp: '0.0.0.0', localOscPort: 1234, @@ -77,6 +103,9 @@ const defaultSettingsReducerState: Array = [ fadeTime: 120, voFadeTime: 280, showPfl: false, + enablePages: true, + pageLength: 16, + mixerOnline: false, serverOnline: true, }, @@ -118,6 +147,13 @@ export const settings = ( case TOGGLE_SHOW_SNAPS: nextState[0].showSnaps = !nextState[0].showSnaps return nextState + case SET_PAGE: + nextState[0].currentPage = { + type: action.pageType, + id: action.id, + start: action.start, + } + return nextState case SET_MIXER_ONLINE: nextState[0].mixerOnline = action.mixerOnline return nextState @@ -126,12 +162,17 @@ export const settings = ( return nextState case UPDATE_SETTINGS: nextState[0] = action.settings + + // ignore UI state: nextState[0].showSettings = state[0].showSettings nextState[0].showOptions = state[0].showOptions nextState[0].showMonitorOptions = state[0].showMonitorOptions nextState[0].showStorage = state[0].showStorage nextState[0].showChanStrip = state[0].showChanStrip nextState[0].serverOnline = state[0].serverOnline + nextState[0].currentPage = state[0].currentPage + nextState[0].customPages = state[0].customPages + if ( typeof MixerProtocolPresets[nextState[0].mixerProtocol] === 'undefined' diff --git a/server/utils/SettingsStorage.ts b/server/utils/SettingsStorage.ts index b879f105..f819442a 100644 --- a/server/utils/SettingsStorage.ts +++ b/server/utils/SettingsStorage.ts @@ -22,7 +22,9 @@ export const loadSettings = (storeRedux: any) => { } export const saveSettings = (settings: any) => { - let json = JSON.stringify(settings) + const settingsCopy = { ...settings } + delete settingsCopy.customPages + let json = JSON.stringify(settingsCopy) if (!fs.existsSync('storage')) { fs.mkdirSync('storage') } @@ -178,3 +180,14 @@ export const setCcgDefault = (fileName: string) => { } }) } + +export const getCustomPages = (): object | undefined => { + try { + return JSON.parse( + fs.readFileSync(path.resolve('storage', 'pages.json')) + ) + } catch (error) { + logger.error('CouldnĀ“t read pages.json file', {}) + return + } +}