diff --git a/css/webamp.css b/css/webamp.css index 280a4d73..4b15138c 100644 --- a/css/webamp.css +++ b/css/webamp.css @@ -4,6 +4,9 @@ position: absolute; top: 0; left: 0; + right: 0; + bottom: 0; + overflow: hidden; } /* Prevent accidental highlighting */ diff --git a/js/__snapshots__/serialization.test.ts.snap b/js/__snapshots__/serialization.test.ts.snap new file mode 100644 index 00000000..a961707a --- /dev/null +++ b/js/__snapshots__/serialization.test.ts.snap @@ -0,0 +1,115 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`can serialize the initial state 1`] = ` +Object { + "display": Object { + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinColors": Array [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)", + ], + "skinCursors": null, + "skinGenLetterWidths": null, + "skinImages": Object { + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=", + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + }, + "skinPlaylistStyle": null, + "skinRegion": Object {}, + "visualizerStyle": 0, + }, + "equalizer": Object { + "auto": false, + "on": true, + "sliders": Object { + "1000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "170": 50, + "3000": 50, + "310": 50, + "60": 50, + "600": 50, + "6000": 50, + "preamp": 50, + }, + }, + "media": Object { + "balance": 0, + "repeat": false, + "shuffle": false, + "volume": 78, + }, + "version": 1, + "windows": Object { + "focused": "main", + "genWindows": Object { + "equalizer": Object { + "hidden": false, + "open": true, + "position": Object { + "x": 0, + "y": 0, + }, + "shade": false, + "size": Array [ + 0, + 0, + ], + }, + "main": Object { + "hidden": false, + "open": true, + "position": Object { + "x": 0, + "y": 0, + }, + "shade": false, + "size": Array [ + 0, + 0, + ], + }, + "playlist": Object { + "hidden": false, + "open": true, + "position": Object { + "x": 0, + "y": 0, + }, + "shade": false, + "size": Array [ + 0, + 0, + ], + }, + }, + "positionsAreRelative": true, + }, +} +`; diff --git a/js/__tests__/fixtures/serializedState/v1/balance.json b/js/__tests__/fixtures/serializedState/v1/balance.json new file mode 100644 index 00000000..2698d1b2 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/balance.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 40, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/double-mode.json b/js/__tests__/fixtures/serializedState/v1/double-mode.json new file mode 100644 index 00000000..f9193bd7 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/double-mode.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": true, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/equalizer-auto.json b/js/__tests__/fixtures/serializedState/v1/equalizer-auto.json new file mode 100644 index 00000000..09e579e9 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/equalizer-auto.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": true, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/equalizer-band.json b/js/__tests__/fixtures/serializedState/v1/equalizer-band.json new file mode 100644 index 00000000..c0eb62e6 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/equalizer-band.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 100, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/equalizer-on.json b/js/__tests__/fixtures/serializedState/v1/equalizer-on.json new file mode 100644 index 00000000..585a01ea --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/equalizer-on.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": false, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/equalizer-preamp.json b/js/__tests__/fixtures/serializedState/v1/equalizer-preamp.json new file mode 100644 index 00000000..65115b13 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/equalizer-preamp.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 10 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/focused-window.json b/js/__tests__/fixtures/serializedState/v1/focused-window.json new file mode 100644 index 00000000..0ec9358b --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/focused-window.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "equalizer" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/llama-mode.json b/js/__tests__/fixtures/serializedState/v1/llama-mode.json new file mode 100644 index 00000000..f761ace8 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/llama-mode.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": true, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/main-window-position.json b/js/__tests__/fixtures/serializedState/v1/main-window-position.json new file mode 100644 index 00000000..bb95446e --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/main-window-position.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 100, + "y": 100 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/repeat.json b/js/__tests__/fixtures/serializedState/v1/repeat.json new file mode 100644 index 00000000..ec16fdaa --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/repeat.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": true + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/shuffle.json b/js/__tests__/fixtures/serializedState/v1/shuffle.json new file mode 100644 index 00000000..18496b2d --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/shuffle.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": true, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/volume.json b/js/__tests__/fixtures/serializedState/v1/volume.json new file mode 100644 index 00000000..ca3bb494 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/volume.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 50, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/window-hidden.json b/js/__tests__/fixtures/serializedState/v1/window-hidden.json new file mode 100644 index 00000000..87555494 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/window-hidden.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": true, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/window-open.json b/js/__tests__/fixtures/serializedState/v1/window-open.json new file mode 100644 index 00000000..63b1a7dd --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/window-open.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": false, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/window-positions-are-relative.json b/js/__tests__/fixtures/serializedState/v1/window-positions-are-relative.json new file mode 100644 index 00000000..c522410c --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/window-positions-are-relative.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": false, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 100, + "y": 100 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/window-shade.json b/js/__tests__/fixtures/serializedState/v1/window-shade.json new file mode 100644 index 00000000..9f1baa59 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/window-shade.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": true, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/__tests__/fixtures/serializedState/v1/window-size.json b/js/__tests__/fixtures/serializedState/v1/window-size.json new file mode 100644 index 00000000..bbc244e2 --- /dev/null +++ b/js/__tests__/fixtures/serializedState/v1/window-size.json @@ -0,0 +1,111 @@ +{ + "version": 1, + "media": { + "volume": 78, + "balance": 0, + "shuffle": false, + "repeat": false + }, + "equalizer": { + "on": true, + "auto": false, + "sliders": { + "60": 50, + "170": 50, + "310": 50, + "600": 50, + "1000": 50, + "3000": 50, + "6000": 50, + "12000": 50, + "14000": 50, + "16000": 50, + "preamp": 50 + } + }, + "display": { + "visualizerStyle": 0, + "doubled": false, + "llama": false, + "marqueeStep": 0, + "skinImages": { + "EQ_PREAMP_LINE": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==", + "EQ_GRAPH_LINE_COLORS": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII=" + }, + "skinCursors": null, + "skinRegion": {}, + "skinGenLetterWidths": null, + "skinColors": [ + "rgb(0,0,0)", + "rgb(24,33,41)", + "rgb(239,49,16)", + "rgb(206,41,16)", + "rgb(214,90,0)", + "rgb(214,102,0)", + "rgb(214,115,0)", + "rgb(198,123,8)", + "rgb(222,165,24)", + "rgb(214,181,33)", + "rgb(189,222,41)", + "rgb(148,222,33)", + "rgb(41,206,16)", + "rgb(50,190,16)", + "rgb(57,181,16)", + "rgb(49,156,8)", + "rgb(41,148,0)", + "rgb(24,132,8)", + "rgb(255,255,255)", + "rgb(214,214,222)", + "rgb(181,189,189)", + "rgb(160,170,175)", + "rgb(148,156,165)", + "rgb(150,150,150)" + ], + "skinPlaylistStyle": null + }, + "windows": { + "positionsAreRelative": true, + "genWindows": { + "main": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "equalizer": { + "size": [ + 0, + 0 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + }, + "playlist": { + "size": [ + 4, + 5 + ], + "open": true, + "hidden": false, + "shade": false, + "position": { + "x": 0, + "y": 0 + } + } + }, + "focused": "main" + } +} \ No newline at end of file diff --git a/js/actionCreators/equalizer.ts b/js/actionCreators/equalizer.ts index fb4b8988..2ef90bc0 100644 --- a/js/actionCreators/equalizer.ts +++ b/js/actionCreators/equalizer.ts @@ -1,6 +1,11 @@ import { BANDS } from "../constants"; -import { SET_EQ_ON, SET_EQ_OFF, SET_BAND_VALUE } from "../actionTypes"; +import { + SET_EQ_ON, + SET_EQ_OFF, + SET_BAND_VALUE, + SET_EQ_AUTO +} from "../actionTypes"; import { Band, Dispatchable } from "../types"; const BAND_SNAP_DISTANCE = 10; @@ -52,3 +57,9 @@ export function toggleEq(): Dispatchable { } }; } + +export function toggleEqAuto(): Dispatchable { + return (dispatch, getState) => { + dispatch({ type: SET_EQ_AUTO, value: !getState().equalizer.auto }); + }; +} diff --git a/js/actionCreators/index.ts b/js/actionCreators/index.ts index 76844812..5142e3b8 100644 --- a/js/actionCreators/index.ts +++ b/js/actionCreators/index.ts @@ -5,9 +5,12 @@ import { CLOSE_REQUESTED, MINIMIZE_WINAMP, SET_FOCUS, - UNSET_FOCUS + UNSET_FOCUS, + LOAD_SERIALIZED_STATE } from "../actionTypes"; import { Dispatchable } from "../types"; +import { ensureWindowsAreOnScreen } from "./windows"; +import { SerializedStateV1 } from "../serializedStates/v1Types"; export { toggleDoubleSizeMode, @@ -19,7 +22,15 @@ export { setWindowSize, toggleWindow, updateWindowPositions, - toggleMainWindowShadeMode + toggleMainWindowShadeMode, + centerWindowsInContainer, + centerWindowsInView, + resetWindowSizes, + browserWindowSizeChanged, + ensureWindowsAreOnScreen, + stackWindows, + toggleLlamaMode, + setFocusedWindow } from "./windows"; export { play, @@ -43,7 +54,8 @@ export { setEqToMid, setEqToMin, setPreamp, - toggleEq + toggleEq, + toggleEqAuto } from "./equalizer"; export { addTracksFromReferences, @@ -108,3 +120,13 @@ export function setFocus(input: string): Dispatchable { export function unsetFocus(): Dispatchable { return { type: UNSET_FOCUS }; } + +export function loadSerializedState( + // In the future this type should be the union of all versioned types. + serializedState: SerializedStateV1 +): Dispatchable { + return dispatch => { + dispatch({ type: LOAD_SERIALIZED_STATE, serializedState }); + dispatch(ensureWindowsAreOnScreen()); + }; +} diff --git a/js/actionCreators/windows.ts b/js/actionCreators/windows.ts index 830e43c0..244cc7da 100644 --- a/js/actionCreators/windows.ts +++ b/js/actionCreators/windows.ts @@ -1,10 +1,6 @@ -import { - getWindowGraph, - getWindowSizes, - getWindowPositions -} from "../selectors"; +import * as Selectors from "../selectors"; -import { objectMap } from "../utils"; +import * as Utils from "../utils"; import { UPDATE_WINDOW_POSITIONS, TOGGLE_DOUBLESIZE_MODE, @@ -12,7 +8,11 @@ import { TOGGLE_WINDOW, CLOSE_WINDOW, TOGGLE_WINDOW_SHADE_MODE, - SET_WINDOW_VISIBILITY + SET_WINDOW_VISIBILITY, + BROWSER_WINDOW_SIZE_CHANGED, + RESET_WINDOW_SIZES, + TOGGLE_LLAMA_MODE, + SET_FOCUSED_WINDOW } from "../actionTypes"; import { getPositionDiff, SizeDiff } from "../resizeUtils"; @@ -28,12 +28,12 @@ import { Action, Dispatchable, WindowId, WindowPositions } from "../types"; function withWindowGraphIntegrity(action: Action): Dispatchable { return (dispatch, getState) => { const state = getState(); - const graph = getWindowGraph(state); - const originalSizes = getWindowSizes(state); + const graph = Selectors.getWindowGraph(state); + const originalSizes = Selectors.getWindowSizes(state); dispatch(action); - const newSizes = getWindowSizes(getState()); + const newSizes = Selectors.getWindowSizes(getState()); const sizeDiff: SizeDiff = {}; for (const window of Object.keys(newSizes)) { const original = originalSizes[window]; @@ -45,9 +45,9 @@ function withWindowGraphIntegrity(action: Action): Dispatchable { } const positionDiff = getPositionDiff(graph, sizeDiff); - const windowPositions = getWindowPositions(state); + const windowPositions = Selectors.getWindowPositions(state); - const newPositions = objectMap(windowPositions, (position, key) => + const newPositions = Utils.objectMap(windowPositions, (position, key) => applyDiff(position, positionDiff[key]) ); @@ -59,6 +59,10 @@ export function toggleDoubleSizeMode(): Dispatchable { return withWindowGraphIntegrity({ type: TOGGLE_DOUBLESIZE_MODE }); } +export function toggleLlamaMode(): Dispatchable { + return { type: TOGGLE_LLAMA_MODE }; +} + export function toggleEqualizerShadeMode(): Dispatchable { return withWindowGraphIntegrity({ type: TOGGLE_WINDOW_SHADE_MODE, @@ -92,6 +96,10 @@ export function showWindow(windowId: WindowId): Dispatchable { return { type: SET_WINDOW_VISIBILITY, windowId, hidden: false }; } +export function setFocusedWindow(window: WindowId): Dispatchable { + return { type: SET_FOCUSED_WINDOW, window }; +} + export function setWindowSize( windowId: WindowId, size: [number, number] @@ -104,7 +112,146 @@ export function toggleWindow(windowId: WindowId): Dispatchable { } export function updateWindowPositions( - positions: WindowPositions + positions: WindowPositions, + absolute?: boolean ): Dispatchable { - return { type: UPDATE_WINDOW_POSITIONS, positions }; + return { type: UPDATE_WINDOW_POSITIONS, positions, absolute }; +} + +export function centerWindowsInContainer(container: HTMLElement): Dispatchable { + return (dispatch, getState) => { + if (!Selectors.getPositionsAreRelative(getState())) { + return; + } + const { left, top } = container.getBoundingClientRect(); + const { scrollWidth: width, scrollHeight: height } = container; + dispatch(centerWindows({ left, top, width, height })); + }; +} + +export function centerWindowsInView(): Dispatchable { + return centerWindows({ + left: window.scrollX, + top: window.scrollY, + width: window.innerWidth, + height: window.innerHeight + }); +} + +export function centerWindows(box: { + left: number; + top: number; + width: number; + height: number; +}): Dispatchable { + return (dispatch, getState) => { + const state = getState(); + const windowsInfo = Selectors.getWindowsInfo(state); + const getOpen = Selectors.getWindowOpen(state); + const { top, left, width, height } = box; + + const offsetLeft = left + window.scrollX; + const offsetTop = top + window.scrollY; + + // A layout has been suplied. We will compute the bounding box and + // center the given layout. + const bounding = Utils.calculateBoundingBox( + windowsInfo.filter(w => getOpen(w.key)) + ); + + const boxHeight = bounding.bottom - bounding.top; + const boxWidth = bounding.right - bounding.left; + + const move = { + x: Math.ceil(offsetLeft - bounding.left + (width - boxWidth) / 2), + y: Math.ceil(offsetTop - bounding.top + (height - boxHeight) / 2) + }; + + const newPositions = windowsInfo.reduce( + (pos, w) => ({ + ...pos, + [w.key]: { x: move.x + w.x, y: move.y + w.y } + }), + {} + ); + + dispatch(updateWindowPositions(newPositions, true)); + }; +} + +export function browserWindowSizeChanged() { + const { height, width } = Utils.getWindowSize(); + return { type: BROWSER_WINDOW_SIZE_CHANGED, height, width }; +} + +export function resetWindowSizes(): Dispatchable { + return { type: RESET_WINDOW_SIZES }; +} + +export function stackWindows(): Dispatchable { + return (dispatch, getState) => { + dispatch( + updateWindowPositions(Selectors.getStackedLayoutPositions(getState())) + ); + }; +} + +export function ensureWindowsAreOnScreen(): Dispatchable { + return (dispatch, getState) => { + const state = getState(); + + const windowsInfo = Selectors.getWindowsInfo(state); + const getOpen = Selectors.getWindowOpen(state); + const { height, width } = Utils.getWindowSize(); + const bounding = Utils.calculateBoundingBox( + windowsInfo.filter(w => getOpen(w.key)) + ); + const positions = Selectors.getWindowPositions(state); + + // Are we good? + if ( + bounding.left >= 0 && + bounding.top >= 0 && + bounding.right <= width && + bounding.bottom <= height + ) { + // My work here is done. + return; + } + + const boundingHeight = bounding.bottom - bounding.top; + const boundingWidth = bounding.right - bounding.left; + + // Could we simply shift all the windows by a constant offset? + if (boundingWidth <= width && boundingHeight <= height) { + let moveY = 0; + let moveX = 0; + if (bounding.top <= 0) { + moveY = bounding.top; + } else if (bounding.bottom > height) { + moveY = bounding.bottom - height; + } + + if (bounding.left <= 0) { + moveX = bounding.left; + } else if (bounding.right > width) { + moveX = bounding.right - width; + } + + const newPositions = Utils.objectMap(positions, position => ({ + x: position.x - moveX, + y: position.y - moveY + })); + + dispatch(updateWindowPositions(newPositions)); + return; + } + + // TODO: Try moving the individual groups to try to fit them in + + // I give up. Just reset everything. + dispatch(resetWindowSizes()); + dispatch(stackWindows()); + dispatch(centerWindowsInView()); + }; } diff --git a/js/actionTypes.ts b/js/actionTypes.ts index ec1ce8f5..2267ba52 100644 --- a/js/actionTypes.ts +++ b/js/actionTypes.ts @@ -71,3 +71,6 @@ export const SET_DUMMY_VIZ_DATA = "SET_DUMMY_VIZ_DATA"; export const SET_WINDOW_VISIBILITY = "SET_WINDOW_VISIBILITY"; export const LOADING = "LOADING"; export const CLOSE_REQUESTED = "CLOSE_REQUESTED"; +export const LOAD_SERIALIZED_STATE = "LOAD_SERIALIZED_STATE"; +export const RESET_WINDOW_SIZES = "RESET_WINDOW_SIZES"; +export const BROWSER_WINDOW_SIZE_CHANGED = "BROWSER_WINDOW_SIZE_CHANGED"; diff --git a/js/components/App.js b/js/components/App.js index 7625cd5f..dc8e2f05 100644 --- a/js/components/App.js +++ b/js/components/App.js @@ -52,7 +52,7 @@ class App extends React.Component { _setFocus() { const binding = this._bindings[this.props.focused]; - if (binding.node) { + if (binding && binding.node) { binding.node.focus(); } } diff --git a/js/components/WindowManager.js b/js/components/WindowManager.js deleted file mode 100644 index a31e5816..00000000 --- a/js/components/WindowManager.js +++ /dev/null @@ -1,220 +0,0 @@ -import React from "react"; -import PropTypes from "prop-types"; -import { connect } from "react-redux"; - -import { - snapDiffManyToMany, - boundingBox, - snapWithinDiff, - snap, - traceConnection, - applyDiff, - applyMultipleDiffs -} from "../snapUtils"; -import { getWindowsInfo, getWindowHidden, getWindowOpen } from "../selectors"; -import { updateWindowPositions } from "../actionCreators"; -import { WINDOW_HEIGHT, WINDOW_WIDTH } from "../constants"; -import { calculateBoundingBox } from "../utils"; - -const abuts = (a, b) => { - // TODO: This is kinda a hack. They should really be touching, not just within snapping distance. - // Also, overlapping should not count. - const wouldMoveTo = snap(a, b); - return wouldMoveTo.x !== undefined || wouldMoveTo.y !== undefined; -}; - -class WindowManager extends React.Component { - componentDidMount() { - this.centerWindows(); - } - - centerWindows = () => { - const { container } = this.props; - - const rect = container.getBoundingClientRect(); - const offsetLeft = rect.left + window.scrollX; - const offsetTop = rect.top + window.scrollY; - const width = container.scrollWidth; - const height = container.scrollHeight; - - if (this.props.windowsInfo.some(w => w.x == null || w.y == null)) { - // Some windows do not have an initial position, so we'll come up - // with your own layout. - const windowPositions = {}; - const keys = this.windowKeys(); - const totalHeight = keys.length * WINDOW_HEIGHT; - const globalOffsetLeft = Math.max(0, width / 2 - WINDOW_WIDTH / 2); - const globalOffsetTop = Math.max(0, height / 2 - totalHeight / 2); - keys.forEach((key, i) => { - const offset = WINDOW_HEIGHT * i; - windowPositions[key] = { - x: Math.ceil(offsetLeft + globalOffsetLeft), - y: Math.ceil(offsetTop + (globalOffsetTop + offset)) - }; - }); - this.props.updateWindowPositions(windowPositions); - } else { - // A layout has been suplied. We will compute the bounding box and - // center the given layout. - const bounding = calculateBoundingBox( - this.props.windowsInfo.filter(w => this.props.getWindowOpen(w.key)) - ); - - const boxHeight = bounding.bottom - bounding.top; - const boxWidth = bounding.right - bounding.left; - - const move = { - x: Math.ceil(offsetLeft + (width - boxWidth) / 2), - y: Math.ceil(offsetTop + (height - boxHeight) / 2) - }; - - const newPositions = this.props.windowsInfo.reduce( - (pos, w) => ({ ...pos, [w.key]: { x: move.x + w.x, y: move.y + w.y } }), - {} - ); - - this.props.updateWindowPositions(newPositions); - } - }; - - movingAndStationaryNodes(key) { - const windows = this.props.windowsInfo.filter( - w => - this.props.windows[w.key] != null && !this.props.getWindowHidden(w.key) - ); - const targetNode = windows.find(node => node.key === key); - - let movingSet = new Set([targetNode]); - // Only the main window brings other windows along. - if (key === "main") { - const findAllConnected = traceConnection(abuts); - movingSet = findAllConnected(windows, targetNode); - } - - const stationary = windows.filter(w => !movingSet.has(w)); - const moving = Array.from(movingSet); - - return [moving, stationary]; - } - - handleMouseDown = (key, e) => { - if (!e.target.classList.contains("draggable")) { - return; - } - // Prevent dragging from highlighting text. - e.preventDefault(); - - const [moving, stationary] = this.movingAndStationaryNodes(key); - - const mouseStart = { x: e.clientX, y: e.clientY }; - // Aparently this is crazy across browsers. - const browserSize = { - width: Math.max( - document.body.scrollWidth, - document.documentElement.scrollWidth, - document.body.offsetWidth, - document.documentElement.offsetWidth, - document.body.clientWidth, - document.documentElement.clientWidth - ), - height: Math.max( - document.body.scrollHeight, - document.documentElement.scrollHeight, - document.body.offsetHeight, - document.documentElement.offsetHeight, - document.body.clientHeight, - document.documentElement.clientHeight - ) - }; - - const box = boundingBox(moving); - - const handleMouseMove = ee => { - const proposedDiff = { - x: ee.clientX - mouseStart.x, - y: ee.clientY - mouseStart.y - }; - - const proposedWindows = moving.map(node => ({ - ...node, - ...applyDiff(node, proposedDiff) - })); - - const proposedBox = { - ...box, - ...applyDiff(box, proposedDiff) - }; - - const snapDiff = snapDiffManyToMany(proposedWindows, stationary); - - const withinDiff = snapWithinDiff(proposedBox, browserSize); - - const finalDiff = applyMultipleDiffs(proposedDiff, snapDiff, withinDiff); - - const windowPositionDiff = moving.reduce((diff, window) => { - diff[window.key] = applyDiff(window, finalDiff); - return diff; - }, {}); - - this.props.updateWindowPositions(windowPositionDiff); - }; - - const removeListeners = () => { - window.removeEventListener("mousemove", handleMouseMove); - window.removeEventListener("mouseup", removeListeners); - }; - - window.addEventListener("mouseup", removeListeners); - window.addEventListener("mousemove", handleMouseMove); - }; - - // Keys for the visible windows - windowKeys() { - // TODO: Iterables can probably do this better. - return Object.keys(this.props.windows).filter( - key => !!this.props.windows[key] - ); - } - - render() { - const style = { - position: "absolute", - top: 0, - left: 0 - }; - - const windows = this.props.windowsInfo.filter( - w => this.props.windows[w.key] - ); - - return windows.map(w => ( -