use reselect
reorganize windows reducer
This commit is contained in:
parent
2f1a60fce7
commit
4429f2a573
54
package-lock.json
generated
54
package-lock.json
generated
|
@ -17,7 +17,6 @@
|
||||||
"express-session": "^1.17.2",
|
"express-session": "^1.17.2",
|
||||||
"image-q": "^4.0.0",
|
"image-q": "^4.0.0",
|
||||||
"js-file-download": "^0.4.12",
|
"js-file-download": "^0.4.12",
|
||||||
"localforage": "^1.10.0",
|
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.4",
|
"multer": "^1.4.4",
|
||||||
"mysql2": "^2.3.3",
|
"mysql2": "^2.3.3",
|
||||||
|
@ -42,6 +41,7 @@
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-thunk": "^2.4.1",
|
"redux-thunk": "^2.4.1",
|
||||||
|
"reselect": "^4.1.6",
|
||||||
"sequelize": "^6.21.3",
|
"sequelize": "^6.21.3",
|
||||||
"sharp": "^0.30.7",
|
"sharp": "^0.30.7",
|
||||||
"startaudiocontext": "^1.2.1",
|
"startaudiocontext": "^1.2.1",
|
||||||
|
@ -6301,11 +6301,6 @@
|
||||||
"@types/node": "16.9.1"
|
"@types/node": "16.9.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/immediate": {
|
|
||||||
"version": "3.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
|
||||||
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
|
||||||
},
|
|
||||||
"node_modules/import-fresh": {
|
"node_modules/import-fresh": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||||
|
@ -7097,14 +7092,6 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lie": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
|
|
||||||
"dependencies": {
|
|
||||||
"immediate": "~3.0.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lines-and-columns": {
|
"node_modules/lines-and-columns": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||||
|
@ -7134,14 +7121,6 @@
|
||||||
"node": ">=8.9.0"
|
"node": ">=8.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/localforage": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
|
|
||||||
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
|
|
||||||
"dependencies": {
|
|
||||||
"lie": "3.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||||
|
@ -9177,6 +9156,11 @@
|
||||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/reselect": {
|
||||||
|
"version": "4.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz",
|
||||||
|
"integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ=="
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.1",
|
"version": "1.22.1",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||||
|
@ -15913,11 +15897,6 @@
|
||||||
"@types/node": "16.9.1"
|
"@types/node": "16.9.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"immediate": {
|
|
||||||
"version": "3.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
|
||||||
"integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
|
|
||||||
},
|
|
||||||
"import-fresh": {
|
"import-fresh": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||||
|
@ -16506,14 +16485,6 @@
|
||||||
"type-check": "~0.4.0"
|
"type-check": "~0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lie": {
|
|
||||||
"version": "3.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
|
|
||||||
"integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
|
|
||||||
"requires": {
|
|
||||||
"immediate": "~3.0.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lines-and-columns": {
|
"lines-and-columns": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||||
|
@ -16537,14 +16508,6 @@
|
||||||
"json5": "^2.1.2"
|
"json5": "^2.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"localforage": {
|
|
||||||
"version": "1.10.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
|
|
||||||
"integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
|
|
||||||
"requires": {
|
|
||||||
"lie": "3.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"locate-path": {
|
"locate-path": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||||
|
@ -18047,6 +18010,11 @@
|
||||||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"reselect": {
|
||||||
|
"version": "4.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz",
|
||||||
|
"integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ=="
|
||||||
|
},
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.22.1",
|
"version": "1.22.1",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
"express-session": "^1.17.2",
|
"express-session": "^1.17.2",
|
||||||
"image-q": "^4.0.0",
|
"image-q": "^4.0.0",
|
||||||
"js-file-download": "^0.4.12",
|
"js-file-download": "^0.4.12",
|
||||||
"localforage": "^1.10.0",
|
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.4",
|
"multer": "^1.4.4",
|
||||||
"mysql2": "^2.3.3",
|
"mysql2": "^2.3.3",
|
||||||
|
@ -56,6 +55,7 @@
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-thunk": "^2.4.1",
|
"redux-thunk": "^2.4.1",
|
||||||
|
"reselect": "^4.1.6",
|
||||||
"sequelize": "^6.21.3",
|
"sequelize": "^6.21.3",
|
||||||
"sharp": "^0.30.7",
|
"sharp": "^0.30.7",
|
||||||
"startaudiocontext": "^1.2.1",
|
"startaudiocontext": "^1.2.1",
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
import createKeyPressHandler from './controls/keypress';
|
import createKeyPressHandler from './controls/keypress';
|
||||||
import {
|
import {
|
||||||
fetchMe,
|
|
||||||
initTimer,
|
initTimer,
|
||||||
urlChange,
|
urlChange,
|
||||||
receiveOnline,
|
receiveOnline,
|
||||||
|
@ -15,6 +14,9 @@ import {
|
||||||
setMobile,
|
setMobile,
|
||||||
windowResize,
|
windowResize,
|
||||||
} from './store/actions';
|
} from './store/actions';
|
||||||
|
import {
|
||||||
|
fetchMe,
|
||||||
|
} from './store/actions/thunks';
|
||||||
import {
|
import {
|
||||||
receivePixelUpdate,
|
receivePixelUpdate,
|
||||||
receivePixelReturn,
|
receivePixelReturn,
|
||||||
|
@ -36,12 +38,12 @@ function init() {
|
||||||
pixels.forEach((pxl) => {
|
pixels.forEach((pxl) => {
|
||||||
const [offset, color] = pxl;
|
const [offset, color] = pxl;
|
||||||
// remove protection
|
// remove protection
|
||||||
receivePixelUpdate(store, i, j, offset, color & 0x7F);
|
receivePixelUpdate(getRenderer(), i, j, offset, color & 0x7F);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
SocketClient.on('pixelReturn',
|
SocketClient.on('pixelReturn', (args) => {
|
||||||
(args) => receivePixelReturn(store, ...args),
|
receivePixelReturn(store, getRenderer(), args);
|
||||||
);
|
});
|
||||||
SocketClient.on('cooldownPacket', (coolDown) => {
|
SocketClient.on('cooldownPacket', (coolDown) => {
|
||||||
store.dispatch(receiveCoolDown(coolDown));
|
store.dispatch(receiveCoolDown(coolDown));
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import useInterval from './hooks/interval';
|
import useInterval from './hooks/interval';
|
||||||
import { showHelpModal } from '../store/actions';
|
import { showHelpModal } from '../store/actions/windows';
|
||||||
import {
|
import {
|
||||||
largeDurationToString,
|
largeDurationToString,
|
||||||
} from '../core/utils';
|
} from '../core/utils';
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import copy from '../utils/clipboard';
|
import copy from '../utils/clipboard';
|
||||||
import { notify } from '../store/actions';
|
import { notify } from '../store/actions/thunks';
|
||||||
|
|
||||||
|
|
||||||
function renderCoordinates(cell) {
|
function renderCoordinates(cell) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import React, { useState } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import { notify } from '../store/actions';
|
import { notify } from '../store/actions/thunks';
|
||||||
import copyTextToClipboard from '../utils/clipboard';
|
import copyTextToClipboard from '../utils/clipboard';
|
||||||
import {
|
import {
|
||||||
requestIID,
|
requestIID,
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import LogInForm from './LogInForm';
|
import LogInForm from './LogInForm';
|
||||||
import { changeWindowType } from '../store/actions';
|
import { changeWindowType } from '../store/actions/windows';
|
||||||
|
|
||||||
const logoStyle = {
|
const logoStyle = {
|
||||||
marginRight: 5,
|
marginRight: 5,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { t } from 'ttag';
|
||||||
import {
|
import {
|
||||||
setBlockingDm,
|
setBlockingDm,
|
||||||
setUserBlock,
|
setUserBlock,
|
||||||
} from '../store/actions';
|
} from '../store/actions/thunks';
|
||||||
import MdToggleButton from './MdToggleButton';
|
import MdToggleButton from './MdToggleButton';
|
||||||
|
|
||||||
const SocialSettings = ({ done }) => {
|
const SocialSettings = ({ done }) => {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {
|
import React, {
|
||||||
useState, useCallback, useRef, useEffect,
|
useState, useCallback, useRef, useEffect, useMemo,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
@ -16,21 +16,26 @@ import {
|
||||||
toggleMaximizeWindow,
|
toggleMaximizeWindow,
|
||||||
cloneWindow,
|
cloneWindow,
|
||||||
focusWindow,
|
focusWindow,
|
||||||
} from '../store/actions';
|
} from '../store/actions/windows';
|
||||||
|
import {
|
||||||
|
makeSelectWindowById,
|
||||||
|
makeSelectWindowPosById,
|
||||||
|
selectShowWindows,
|
||||||
|
} from '../store/selectors/windows';
|
||||||
import useDrag from './hooks/drag';
|
import useDrag from './hooks/drag';
|
||||||
import COMPONENTS from './windows';
|
import COMPONENTS from './windows';
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
const selectWindowById = (state, windowId) => state.windows.windows.find((win) => win.windowId === windowId);
|
|
||||||
|
|
||||||
const Window = ({ id }) => {
|
const Window = ({ id }) => {
|
||||||
const [render, setRender] = useState(false);
|
const [render, setRender] = useState(false);
|
||||||
|
|
||||||
const titleBarRef = useRef(null);
|
const titleBarRef = useRef(null);
|
||||||
const resizeRef = useRef(null);
|
const resizeRef = useRef(null);
|
||||||
|
|
||||||
const win = useSelector((state) => selectWindowById(state, id));
|
const selectWindowById = useMemo(() => makeSelectWindowById(id), []);
|
||||||
const showWindows = useSelector((state) => state.windows.showWindows);
|
const selectWIndowPosById = useMemo(() => makeSelectWindowPosById(id), []);
|
||||||
|
const win = useSelector(selectWindowById);
|
||||||
|
const position = useSelector(selectWIndowPosById);
|
||||||
|
const showWindows = useSelector(selectShowWindows);
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
@ -101,12 +106,14 @@ const Window = ({ id }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
width, height,
|
|
||||||
xPos, yPos,
|
|
||||||
windowType,
|
windowType,
|
||||||
z,
|
|
||||||
title,
|
title,
|
||||||
} = win;
|
} = win;
|
||||||
|
const {
|
||||||
|
xPos, yPos,
|
||||||
|
width, height,
|
||||||
|
z,
|
||||||
|
} = position;
|
||||||
|
|
||||||
const [Content, name] = COMPONENTS[windowType];
|
const [Content, name] = COMPONENTS[windowType];
|
||||||
|
|
||||||
|
@ -155,10 +162,6 @@ const Window = ({ id }) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!showWindows) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`window ${extraClasses}`}
|
className={`window ${extraClasses}`}
|
||||||
|
|
|
@ -9,29 +9,21 @@ import Window from './Window';
|
||||||
import Overlay from './Overlay';
|
import Overlay from './Overlay';
|
||||||
import {
|
import {
|
||||||
closeFullscreenWindows,
|
closeFullscreenWindows,
|
||||||
} from '../store/actions';
|
} from '../store/actions/windows';
|
||||||
|
import {
|
||||||
// eslint-disable-next-line max-len
|
selectIfFullscreen,
|
||||||
const selectWindowIds = (state) => state.windows.windows.map((win) => win.windowId);
|
selectActiveWindowIds,
|
||||||
// eslint-disable-next-line max-len
|
} from '../store/selectors/windows';
|
||||||
const selectMeta = (state) => {
|
|
||||||
console.log('check');
|
|
||||||
return [
|
|
||||||
state.windows.showWindows,
|
|
||||||
state.windows.someFullscreen,
|
|
||||||
state.windows.windows.some((win) => win.fullscreen && win.open && !win.hidden),
|
|
||||||
]};
|
|
||||||
|
|
||||||
const WindowManager = () => {
|
const WindowManager = () => {
|
||||||
const windowIds = useSelector(selectWindowIds, shallowEqual);
|
const windowIds = useSelector(selectActiveWindowIds, shallowEqual);
|
||||||
const [
|
const [
|
||||||
showWindows,
|
fullscreenExistOrShowWindows,
|
||||||
someFullscreen,
|
|
||||||
someOpenFullscreen,
|
someOpenFullscreen,
|
||||||
] = useSelector(selectMeta, shallowEqual);
|
] = useSelector(selectIfFullscreen, shallowEqual);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
if ((!showWindows && !someFullscreen) || !windowIds.length) {
|
if (!fullscreenExistOrShowWindows || !windowIds.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
||||||
import { FaFlipboard } from 'react-icons/fa';
|
import { FaFlipboard } from 'react-icons/fa';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import { showCanvasSelectionModal } from '../../store/actions';
|
import { showCanvasSelectionModal } from '../../store/actions/windows';
|
||||||
|
|
||||||
|
|
||||||
const CanvasSwitchButton = () => {
|
const CanvasSwitchButton = () => {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { t } from 'ttag';
|
||||||
import {
|
import {
|
||||||
hideAllWindowTypes,
|
hideAllWindowTypes,
|
||||||
openChatWindow,
|
openChatWindow,
|
||||||
} from '../../store/actions';
|
} from '../../store/actions/windows';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return [ chatOpen, chatHiden ]
|
* return [ chatOpen, chatHiden ]
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
||||||
import { FaQuestion } from 'react-icons/fa';
|
import { FaQuestion } from 'react-icons/fa';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import { showHelpModal } from '../../store/actions';
|
import { showHelpModal } from '../../store/actions/windows';
|
||||||
|
|
||||||
|
|
||||||
const HelpButton = () => {
|
const HelpButton = () => {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
||||||
import { MdPerson } from 'react-icons/md';
|
import { MdPerson } from 'react-icons/md';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import { showUserAreaModal } from '../../store/actions';
|
import { showUserAreaModal } from '../../store/actions/windows';
|
||||||
|
|
||||||
|
|
||||||
const LogInButton = () => {
|
const LogInButton = () => {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
||||||
import { FaCog } from 'react-icons/fa';
|
import { FaCog } from 'react-icons/fa';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import { showSettingsModal } from '../../store/actions';
|
import { showSettingsModal } from '../../store/actions/windows';
|
||||||
|
|
||||||
|
|
||||||
const SettingsButton = () => {
|
const SettingsButton = () => {
|
||||||
|
|
|
@ -11,10 +11,12 @@ import {
|
||||||
} from '../hooks/clickOutside';
|
} from '../hooks/clickOutside';
|
||||||
import {
|
import {
|
||||||
hideContextMenu,
|
hideContextMenu,
|
||||||
setLeaveChannel,
|
|
||||||
muteChatChannel,
|
muteChatChannel,
|
||||||
unmuteChatChannel,
|
unmuteChatChannel,
|
||||||
} from '../../store/actions';
|
} from '../../store/actions';
|
||||||
|
import {
|
||||||
|
setLeaveChannel,
|
||||||
|
} from '../../store/actions/thunks';
|
||||||
|
|
||||||
const ChannelContextMenu = () => {
|
const ChannelContextMenu = () => {
|
||||||
const wrapperRef = useRef(null);
|
const wrapperRef = useRef(null);
|
||||||
|
|
|
@ -11,11 +11,15 @@ import {
|
||||||
} from '../hooks/clickOutside';
|
} from '../hooks/clickOutside';
|
||||||
import {
|
import {
|
||||||
hideContextMenu,
|
hideContextMenu,
|
||||||
addToChatInputMessage,
|
} from '../../store/actions';
|
||||||
|
import {
|
||||||
startDm,
|
startDm,
|
||||||
setUserBlock,
|
setUserBlock,
|
||||||
|
} from '../../store/actions/thunks';
|
||||||
|
import {
|
||||||
|
addToChatInputMessage,
|
||||||
setWindowArgs,
|
setWindowArgs,
|
||||||
} from '../../store/actions';
|
} from '../../store/actions/windows';
|
||||||
import { escapeMd } from '../../core/utils';
|
import { escapeMd } from '../../core/utils';
|
||||||
|
|
||||||
const UserContextMenu = () => {
|
const UserContextMenu = () => {
|
||||||
|
|
|
@ -7,7 +7,8 @@ import { useDispatch, useSelector, shallowEqual } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import CanvasItem from '../CanvasItem';
|
import CanvasItem from '../CanvasItem';
|
||||||
import { changeWindowType, selectCanvas } from '../../store/actions';
|
import { selectCanvas } from '../../store/actions';
|
||||||
|
import { changeWindowType } from '../../store/actions/windows';
|
||||||
|
|
||||||
|
|
||||||
const CanvasSelect = ({ windowId }) => {
|
const CanvasSelect = ({ windowId }) => {
|
||||||
|
|
|
@ -13,13 +13,17 @@ import ChatMessage from '../ChatMessage';
|
||||||
import ChannelDropDown from '../contextmenus/ChannelDropDown';
|
import ChannelDropDown from '../contextmenus/ChannelDropDown';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
showUserAreaModal,
|
|
||||||
fetchChatMessages,
|
|
||||||
showContextMenu,
|
showContextMenu,
|
||||||
setWindowTitle,
|
|
||||||
setWindowArgs,
|
|
||||||
markChannelAsRead,
|
markChannelAsRead,
|
||||||
} from '../../store/actions';
|
} from '../../store/actions';
|
||||||
|
import {
|
||||||
|
showUserAreaModal,
|
||||||
|
setWindowTitle,
|
||||||
|
setWindowArgs,
|
||||||
|
} from '../../store/actions/windows';
|
||||||
|
import {
|
||||||
|
fetchChatMessages,
|
||||||
|
} from '../../store/actions/thunks';
|
||||||
import SocketClient from '../../socket/SocketClient';
|
import SocketClient from '../../socket/SocketClient';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import React, { useState } from 'react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import { changeWindowType } from '../../store/actions';
|
import { changeWindowType } from '../../store/actions/windows';
|
||||||
import { validateEMail } from '../../utils/validation';
|
import { validateEMail } from '../../utils/validation';
|
||||||
import { requestNewPassword } from '../../store/actions/fetch';
|
import { requestNewPassword } from '../../store/actions/fetch';
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,8 @@ import {
|
||||||
} from '../../utils/validation';
|
} from '../../utils/validation';
|
||||||
import { requestRegistration } from '../../store/actions/fetch';
|
import { requestRegistration } from '../../store/actions/fetch';
|
||||||
|
|
||||||
import { changeWindowType, loginUser } from '../../store/actions';
|
import { loginUser } from '../../store/actions';
|
||||||
|
import { changeWindowType } from '../../store/actions/windows';
|
||||||
|
|
||||||
|
|
||||||
function validate(name, email, password, confirmPassword) {
|
function validate(name, email, password, confirmPassword) {
|
||||||
|
|
|
@ -8,8 +8,10 @@ import { t } from 'ttag';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
fetchStats,
|
fetchStats,
|
||||||
|
} from '../../store/actions/thunks';
|
||||||
|
import {
|
||||||
setWindowArgs,
|
setWindowArgs,
|
||||||
} from '../../store/actions';
|
} from '../../store/actions/windows';
|
||||||
import useInterval from '../hooks/interval';
|
import useInterval from '../hooks/interval';
|
||||||
import LogInArea from '../LogInArea';
|
import LogInArea from '../LogInArea';
|
||||||
import Tabs from '../Tabs';
|
import Tabs from '../Tabs';
|
||||||
|
|
|
@ -243,6 +243,7 @@ class PixelPlainterControls {
|
||||||
const [i, j] = getChunkOfPixel(canvasSize, x, y);
|
const [i, j] = getChunkOfPixel(canvasSize, x, y);
|
||||||
const offset = getOffsetOfPixel(canvasSize, x, y);
|
const offset = getOffsetOfPixel(canvasSize, x, y);
|
||||||
tryPlacePixel(
|
tryPlacePixel(
|
||||||
|
renderer,
|
||||||
store,
|
store,
|
||||||
i, j, offset,
|
i, j, offset,
|
||||||
selectedColor,
|
selectedColor,
|
||||||
|
|
|
@ -9,9 +9,11 @@ import {
|
||||||
toggleHiddenCanvases,
|
toggleHiddenCanvases,
|
||||||
togglePixelNotify,
|
togglePixelNotify,
|
||||||
toggleMute,
|
toggleMute,
|
||||||
notify,
|
|
||||||
selectCanvas,
|
selectCanvas,
|
||||||
} from '../store/actions';
|
} from '../store/actions';
|
||||||
|
import {
|
||||||
|
notify,
|
||||||
|
} from '../store/actions/thunks';
|
||||||
|
|
||||||
const usedKeys = ['g', 'h', 'x', 'm', 'r', 'p'];
|
const usedKeys = ['g', 'h', 'x', 'm', 'r', 'p'];
|
||||||
|
|
||||||
|
|
|
@ -248,8 +248,7 @@ class SocketClient extends EventEmitter {
|
||||||
`Socket is closed. Reconnect will be attempted in ${timeout} ms.`,
|
`Socket is closed. Reconnect will be attempted in ${timeout} ms.`,
|
||||||
e.reason,
|
e.reason,
|
||||||
);
|
);
|
||||||
|
setTimeout(() => this.connect(), timeout);
|
||||||
setTimeout(() => this.connect(), 5000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reconnect() {
|
reconnect() {
|
||||||
|
|
|
@ -9,13 +9,13 @@ export default {
|
||||||
const coolDownSeconds = data.getInt16(6);
|
const coolDownSeconds = data.getInt16(6);
|
||||||
const pxlCnt = data.getUint8(8);
|
const pxlCnt = data.getUint8(8);
|
||||||
const rankedPxlCnt = data.getUint8(9);
|
const rankedPxlCnt = data.getUint8(9);
|
||||||
return [
|
return {
|
||||||
retCode,
|
retCode,
|
||||||
wait,
|
wait,
|
||||||
coolDownSeconds,
|
coolDownSeconds,
|
||||||
pxlCnt,
|
pxlCnt,
|
||||||
rankedPxlCnt,
|
rankedPxlCnt,
|
||||||
];
|
};
|
||||||
},
|
},
|
||||||
dehydrate(
|
dehydrate(
|
||||||
retCode,
|
retCode,
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
# Actions
|
|
||||||
|
|
||||||
List of redux actions for reference:
|
|
||||||
|
|
||||||
```js
|
|
||||||
export type Action =
|
|
||||||
{ type: 'LOGGED_OUT' }
|
|
||||||
| { type: 'ALERT',
|
|
||||||
title: string,
|
|
||||||
message: string,
|
|
||||||
alertType: string,
|
|
||||||
btn: string,
|
|
||||||
}
|
|
||||||
| { type: 'CLOSE_ALERT' }
|
|
||||||
| { type: 'TOGGLE_GRID' }
|
|
||||||
| { type: 'TOGGLE_PIXEL_NOTIFY' }
|
|
||||||
| { type: 'TOGGLE_AUTO_ZOOM_IN' }
|
|
||||||
| { type: 'TOGGLE_ONLINE_CANVAS' }
|
|
||||||
| { type: 'TOGGLE_MUTE' }
|
|
||||||
| { type: 'TOGGLE_OPEN_PALETTE' }
|
|
||||||
| { type: 'TOGGLE_COMPACT_PALETTE' }
|
|
||||||
| { type: 'TOGGLE_CHAT_NOTIFY' }
|
|
||||||
| { type: 'TOGGLE_POTATO_MODE' }
|
|
||||||
| { type: 'TOGGLE_LIGHT_GRID' }
|
|
||||||
| { type: 'TOGGLE_OPEN_MENU' }
|
|
||||||
| { type: 'TOGGLE_HISTORICAL_VIEW' }
|
|
||||||
| { type: 'SELECT_STYLE', style: string }
|
|
||||||
| { type: 'SET_NOTIFICATION', notification: string }
|
|
||||||
| { type: 'UNSET_NOTIFICATION' }
|
|
||||||
| { type: 'SET_REQUESTING_PIXEL', requestingPixel: boolean }
|
|
||||||
| { type: 'SET_HOVER', hover: Array }
|
|
||||||
| { type: 'UNSET_HOVER' }
|
|
||||||
| { type: 'SET_WAIT', wait: ?number }
|
|
||||||
| { type: 'RECEIVE_COOLDOWN', wait: number }
|
|
||||||
| { type: 'SET_MOBILE', mobile: boolean }
|
|
||||||
| { type: 'WINDOW_RESIZE'}
|
|
||||||
| { type: 'COOLDOWN_END' }
|
|
||||||
| { type: 'COOLDOWN_SET', coolDown: number }
|
|
||||||
| { type: 'COOLDOWN_DELTA', delta: number }
|
|
||||||
| { type: 'SELECT_COLOR', color: ColorIndex }
|
|
||||||
| { type: 'SELECT_CANVAS', canvasId: number }
|
|
||||||
| { type: 'PLACED_PIXELS', amount: number }
|
|
||||||
| { type: 'PIXEL_WAIT' }
|
|
||||||
| { type: 'SET_VIEW_COORDINATES', view: Array }
|
|
||||||
| { type: 'SET_SCALE', scale: number, zoompoint: Array }
|
|
||||||
| { type: 'REQUEST_BIG_CHUNK', center: Array }
|
|
||||||
| { type: 'PRE_LOADED_BIG_CHUNK', center: Array }
|
|
||||||
| { type: 'RECEIVE_BIG_CHUNK', center: Array, chunk: Uint8Array }
|
|
||||||
| { type: 'RECEIVE_BIG_CHUNK_FAILURE', center: Array, error: Error }
|
|
||||||
| { type: 'UPDATE_PIXEL',
|
|
||||||
i: number,
|
|
||||||
j: number,
|
|
||||||
offset: number,
|
|
||||||
color: ColorIndex,
|
|
||||||
notify: boolean,
|
|
||||||
}
|
|
||||||
| { type: 'RECEIVE_ONLINE', online: number }
|
|
||||||
| { type: 'RECEIVE_CHAT_MESSAGE',
|
|
||||||
name: string,
|
|
||||||
text: string,
|
|
||||||
country: string,
|
|
||||||
channel: number,
|
|
||||||
user: number,
|
|
||||||
isPing: boolean,
|
|
||||||
isRead: boolean,
|
|
||||||
}
|
|
||||||
| { type: 'RECEIVE_CHAT_HISTORY', cid: number, history: Array }
|
|
||||||
| { type: 'OPEN_CHAT_CHANNEL', cid: number }
|
|
||||||
| { type: 'CLOSE_CHAT_CHANNEL', cid: number }
|
|
||||||
| { type: 'ADD_CHAT_CHANNEL', channel: Object }
|
|
||||||
| { type: 'REMOVE_CHAT_CHANNEL', cid: number }
|
|
||||||
| { type: 'MUTE_CHAT_CHANNEL', cid: number }
|
|
||||||
| { type: 'UNMUTE_CHAT_CHANNEL', cid: number }
|
|
||||||
| { type: 'MARK_CHANNEL_AS_READ', cid: number }
|
|
||||||
| { type: 'SET_CHAT_FETCHING', fetching: boolean }
|
|
||||||
| { type: 'OPEN_WINDOW',
|
|
||||||
windowType: string,
|
|
||||||
title: string,
|
|
||||||
fullscreen: boolean,
|
|
||||||
cloneable: boolean,
|
|
||||||
args: Object,
|
|
||||||
}
|
|
||||||
| { type: 'CLOSE_WINDOW', windowId: number }
|
|
||||||
| { type: 'REMOVE_WINDOW', windowId: number }
|
|
||||||
| { type: 'HIDE_ALL_WINDOW_TYPE', windowType: string, hide: boolean }
|
|
||||||
| { type: 'CLOSE_ALL_WINDOW_TYPE', windowType: string}
|
|
||||||
| { type: 'FOCUS_WINDOW', windowId: number }
|
|
||||||
| { type: 'CLONE_WINDOW', windowId: number }
|
|
||||||
| { type: 'TOGGLE_MAXIMIZE_WINDOW', windowId: number }
|
|
||||||
| { type: 'CLOSE_FULLSCREEN_WINDOWS' }
|
|
||||||
| { type: 'MOVE_WINDOW', windowId: number, xDiff: number, yDiff: number }
|
|
||||||
| { type: 'RESIZE_WINDOW', windowId: number, xDiff: number, yDiff: number }
|
|
||||||
| { type: 'CHANGE_WINDOW_TYPE',
|
|
||||||
windowId: number,
|
|
||||||
windowType: number,
|
|
||||||
args: Object,
|
|
||||||
}
|
|
||||||
| { type: 'SET_WINDOW_TITLE', windowId: number, title: string }
|
|
||||||
| { type: 'BLOCK_USER', userId: number, userName: string }
|
|
||||||
| { type: 'UNBLOCK_USER', userId: number, userName: string }
|
|
||||||
| { type: 'SET_BLOCKING_DM', blockDm: boolean }
|
|
||||||
| { type: 'RECEIVE_ME',
|
|
||||||
name: string,
|
|
||||||
waitSeconds: number,
|
|
||||||
messages: Array,
|
|
||||||
mailreg: boolean,
|
|
||||||
totalPixels: number,
|
|
||||||
dailyTotalPixels: number,
|
|
||||||
ranking: number,
|
|
||||||
dailyRanking: number,
|
|
||||||
blockDm: boolean,
|
|
||||||
canvases: Object,
|
|
||||||
channels: Object,
|
|
||||||
blocked: Array,
|
|
||||||
userlvl: number,
|
|
||||||
}
|
|
||||||
| { type: 'LOGIN',
|
|
||||||
name: string,
|
|
||||||
waitSeconds: number,
|
|
||||||
messages: Array,
|
|
||||||
mailreg: boolean,
|
|
||||||
totalPixels: number,
|
|
||||||
dailyTotalPixels: number,
|
|
||||||
ranking: number,
|
|
||||||
dailyRanking: number,
|
|
||||||
blockDm: boolean,
|
|
||||||
canvases: Object,
|
|
||||||
channels: Object,
|
|
||||||
blocked: Array,
|
|
||||||
userlvl: number,
|
|
||||||
}
|
|
||||||
| { type: 'LOGOUT' }
|
|
||||||
| { type: 'RECEIVE_STATS', totalRanking: Object, totalDailyRanking: Object }
|
|
||||||
| { type: 'SET_NAME', name: string }
|
|
||||||
| { type: 'SET_MAILREG', mailreg: boolean }
|
|
||||||
| { type: 'REM_FROM_MESSAGES', message: string }
|
|
||||||
| { type: 'SHOW_CONTEXT_MENU',
|
|
||||||
menuType: string,
|
|
||||||
xPos: number,
|
|
||||||
yPos: number,
|
|
||||||
args: Object,
|
|
||||||
}
|
|
||||||
| { type: 'HIDE_CONTEXT_MENU' }
|
|
||||||
| { type: 'RELOAD_URL' }
|
|
||||||
| { type: 'SET_HISTORICAL_TIME', date: string, time: string }
|
|
||||||
| { type: 'ON_VIEW_FINISH_CHANGE' };
|
|
||||||
|
|
||||||
```
|
|
|
@ -1,14 +1,5 @@
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
|
|
||||||
import {
|
|
||||||
requestStartDm,
|
|
||||||
requestBlock,
|
|
||||||
requestBlockDm,
|
|
||||||
requestLeaveChan,
|
|
||||||
requestRankings,
|
|
||||||
requestMe,
|
|
||||||
} from './fetch';
|
|
||||||
|
|
||||||
export function pAlert(
|
export function pAlert(
|
||||||
title,
|
title,
|
||||||
message,
|
message,
|
||||||
|
@ -115,27 +106,10 @@ export function toggleOpenMenu() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
export function setAllowSettingPixel(allowSettingPixel) {
|
||||||
* requestingPixel is inveted, it has the meaning of
|
|
||||||
* "can i request a pixel"
|
|
||||||
*/
|
|
||||||
export function setRequestingPixel(requestingPixel) {
|
|
||||||
return {
|
return {
|
||||||
type: 'SET_REQUESTING_PIXEL',
|
type: 'ALLOW_SETTING_PIXEL',
|
||||||
requestingPixel,
|
allowSettingPixel,
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setNotification(notification) {
|
|
||||||
return {
|
|
||||||
type: 'SET_NOTIFICATION',
|
|
||||||
notification,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unsetNotification() {
|
|
||||||
return {
|
|
||||||
type: 'UNSET_NOTIFICATION',
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,13 +126,6 @@ export function unsetHover() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setWait(wait) {
|
|
||||||
return {
|
|
||||||
type: 'SET_WAIT',
|
|
||||||
wait,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setMobile(mobile) {
|
export function setMobile(mobile) {
|
||||||
return {
|
return {
|
||||||
type: 'SET_MOBILE',
|
type: 'SET_MOBILE',
|
||||||
|
@ -186,61 +153,6 @@ export function selectCanvas(canvasId) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function placedPixels(amount) {
|
|
||||||
return {
|
|
||||||
type: 'PLACED_PIXELS',
|
|
||||||
amount,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function pixelWait() {
|
|
||||||
return {
|
|
||||||
type: 'PIXEL_WAIT',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function receiveOnline(online) {
|
|
||||||
return {
|
|
||||||
type: 'RECEIVE_ONLINE',
|
|
||||||
online,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function receiveChatMessage(
|
|
||||||
name,
|
|
||||||
text,
|
|
||||||
country,
|
|
||||||
channel,
|
|
||||||
user,
|
|
||||||
isPing,
|
|
||||||
isRead,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'RECEIVE_CHAT_MESSAGE',
|
|
||||||
name,
|
|
||||||
text,
|
|
||||||
country,
|
|
||||||
channel,
|
|
||||||
user,
|
|
||||||
isPing,
|
|
||||||
isRead,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let lastNotify = null;
|
|
||||||
export function notify(notification) {
|
|
||||||
return async (dispatch) => {
|
|
||||||
dispatch(setNotification(notification));
|
|
||||||
if (lastNotify) {
|
|
||||||
clearTimeout(lastNotify);
|
|
||||||
lastNotify = null;
|
|
||||||
}
|
|
||||||
lastNotify = setTimeout(() => {
|
|
||||||
dispatch(unsetNotification());
|
|
||||||
}, 1500);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setViewCoordinates(view) {
|
export function setViewCoordinates(view) {
|
||||||
return {
|
return {
|
||||||
type: 'SET_VIEW_COORDINATES',
|
type: 'SET_VIEW_COORDINATES',
|
||||||
|
@ -358,38 +270,6 @@ export function receiveCoolDown(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* draw pixel on canvas
|
|
||||||
* @param i, j, offset Chunk and offset in chunk
|
|
||||||
* @param color integer Color Index
|
|
||||||
* @param notifyPxl Bool if pixel notification appears (false when my own pixel)
|
|
||||||
*/
|
|
||||||
export function updatePixel(
|
|
||||||
i,
|
|
||||||
j,
|
|
||||||
offset,
|
|
||||||
color,
|
|
||||||
notifyPxl = true,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'UPDATE_PIXEL',
|
|
||||||
i,
|
|
||||||
j,
|
|
||||||
offset,
|
|
||||||
color,
|
|
||||||
notify: notifyPxl,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loginUser(
|
|
||||||
me,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'LOGIN',
|
|
||||||
...me,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function receiveMe(
|
export function receiveMe(
|
||||||
me,
|
me,
|
||||||
) {
|
) {
|
||||||
|
@ -399,13 +279,6 @@ export function receiveMe(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function logoutUser(
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'LOGOUT',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function receiveStats(
|
export function receiveStats(
|
||||||
rankings,
|
rankings,
|
||||||
) {
|
) {
|
||||||
|
@ -417,6 +290,58 @@ export function receiveStats(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function receiveOnline(online) {
|
||||||
|
return {
|
||||||
|
type: 'RECEIVE_ONLINE',
|
||||||
|
online,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function receiveChatMessage(
|
||||||
|
name,
|
||||||
|
text,
|
||||||
|
country,
|
||||||
|
channel,
|
||||||
|
user,
|
||||||
|
isPing,
|
||||||
|
isRead,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: 'RECEIVE_CHAT_MESSAGE',
|
||||||
|
name,
|
||||||
|
text,
|
||||||
|
country,
|
||||||
|
channel,
|
||||||
|
user,
|
||||||
|
isPing,
|
||||||
|
isRead,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check socket/packets/PixelReturn.js for args
|
||||||
|
*/
|
||||||
|
export function storeReceivePixelReturn(args) {
|
||||||
|
args.type = 'RECEIVE_PIXEL_RETURN';
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function logoutUser(
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: 'LOGOUT',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loginUser(
|
||||||
|
me,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: 'LOGIN',
|
||||||
|
...me,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function setName(
|
export function setName(
|
||||||
name,
|
name,
|
||||||
) {
|
) {
|
||||||
|
@ -444,35 +369,6 @@ export function remFromMessages(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchStats() {
|
|
||||||
return async (dispatch) => {
|
|
||||||
const rankings = await requestRankings();
|
|
||||||
if (!rankings.errors) {
|
|
||||||
dispatch(receiveStats(rankings));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchMe() {
|
|
||||||
return async (dispatch) => {
|
|
||||||
const me = await requestMe();
|
|
||||||
if (!me.errors) {
|
|
||||||
dispatch(receiveMe(me));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function receiveChatHistory(
|
|
||||||
cid,
|
|
||||||
history,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'RECEIVE_CHAT_HISTORY',
|
|
||||||
cid,
|
|
||||||
history,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function markChannelAsRead(
|
export function markChannelAsRead(
|
||||||
cid,
|
cid,
|
||||||
) {
|
) {
|
||||||
|
@ -482,42 +378,6 @@ export function markChannelAsRead(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setChatFetching(fetching) {
|
|
||||||
return {
|
|
||||||
type: 'SET_CHAT_FETCHING',
|
|
||||||
fetching,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setApiFetching(fetching) {
|
|
||||||
return {
|
|
||||||
type: 'SET_API_FETCHING',
|
|
||||||
fetching,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchChatMessages(
|
|
||||||
cid,
|
|
||||||
) {
|
|
||||||
return async (dispatch) => {
|
|
||||||
dispatch(setChatFetching(true));
|
|
||||||
const response = await fetch(`api/chathistory?cid=${cid}&limit=50`, {
|
|
||||||
credentials: 'include',
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* timeout in order to not spam api requests and get rate limited
|
|
||||||
*/
|
|
||||||
if (response.ok) {
|
|
||||||
setTimeout(() => { dispatch(setChatFetching(false)); }, 500);
|
|
||||||
const { history } = await response.json();
|
|
||||||
dispatch(receiveChatHistory(cid, history));
|
|
||||||
} else {
|
|
||||||
setTimeout(() => { dispatch(setChatFetching(false)); }, 5000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCoolDown(coolDown) {
|
function setCoolDown(coolDown) {
|
||||||
return {
|
return {
|
||||||
type: 'COOLDOWN_SET',
|
type: 'COOLDOWN_SET',
|
||||||
|
@ -560,132 +420,6 @@ export function initTimer() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* fullscreen means to open as modal
|
|
||||||
* Look into store/reducers/windows.js to know what it means
|
|
||||||
*/
|
|
||||||
export function openWindow(
|
|
||||||
windowType,
|
|
||||||
title = '',
|
|
||||||
args = null,
|
|
||||||
fullscreen = false,
|
|
||||||
cloneable = true,
|
|
||||||
xPos = null,
|
|
||||||
yPos = null,
|
|
||||||
width = null,
|
|
||||||
height = null,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'OPEN_WINDOW',
|
|
||||||
windowType,
|
|
||||||
title,
|
|
||||||
args,
|
|
||||||
fullscreen,
|
|
||||||
cloneable,
|
|
||||||
xPos,
|
|
||||||
yPos,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setWindowArgs(
|
|
||||||
windowId,
|
|
||||||
args,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'SET_WINDOW_ARGS',
|
|
||||||
windowId,
|
|
||||||
args,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function showFullscreenWindow(modalType, title) {
|
|
||||||
return openWindow(
|
|
||||||
modalType,
|
|
||||||
title,
|
|
||||||
null,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function closeFullscreenWindows() {
|
|
||||||
return {
|
|
||||||
type: 'CLOSE_FULLSCREEN_WINDOWS',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showSettingsModal() {
|
|
||||||
return showFullscreenWindow(
|
|
||||||
'SETTINGS',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showUserAreaModal() {
|
|
||||||
return showFullscreenWindow(
|
|
||||||
'USERAREA',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function changeWindowType(
|
|
||||||
windowId,
|
|
||||||
windowType,
|
|
||||||
title = '',
|
|
||||||
args = null,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'CHANGE_WINDOW_TYPE',
|
|
||||||
windowId,
|
|
||||||
windowType,
|
|
||||||
title,
|
|
||||||
args,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setWindowTitle(windowId, title) {
|
|
||||||
return {
|
|
||||||
type: 'SET_WINDOW_TITLE',
|
|
||||||
windowId,
|
|
||||||
title,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showRegisterModal() {
|
|
||||||
return showFullscreenWindow(
|
|
||||||
'REGISTER',
|
|
||||||
t`Register New Account`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showForgotPasswordModal() {
|
|
||||||
return showFullscreenWindow(
|
|
||||||
'FORGOT_PASSWORD',
|
|
||||||
t`Restore my Password`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showHelpModal() {
|
|
||||||
return showFullscreenWindow(
|
|
||||||
'HELP',
|
|
||||||
t`Welcome to PixelPlanet.fun`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export function showArchiveModal() {
|
|
||||||
return showFullscreenWindow(
|
|
||||||
'ARCHIVE',
|
|
||||||
t`Look at past Canvases`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showCanvasSelectionModal() {
|
|
||||||
return showFullscreenWindow(
|
|
||||||
'CANVAS_SELECTION',
|
|
||||||
'',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showContextMenu(
|
export function showContextMenu(
|
||||||
menuType,
|
menuType,
|
||||||
xPos,
|
xPos,
|
||||||
|
@ -766,213 +500,6 @@ export function unmuteChatChannel(cid) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addToChatInputMessage(windowId, msg, focus = true) {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const args = getState().windows.args[windowId];
|
|
||||||
let inputMessage = args && args.inputMessage;
|
|
||||||
if (!inputMessage) {
|
|
||||||
inputMessage = '';
|
|
||||||
} else if (inputMessage.slice(-1) !== ' ') {
|
|
||||||
inputMessage += ' ';
|
|
||||||
}
|
|
||||||
inputMessage += msg;
|
|
||||||
|
|
||||||
dispatch(setWindowArgs(windowId, {
|
|
||||||
inputMessage,
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (focus) {
|
|
||||||
const inputElem = document.getElementById(`chtipt-${windowId}`);
|
|
||||||
if (inputElem) {
|
|
||||||
inputElem.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function closeWindow(windowId) {
|
|
||||||
return {
|
|
||||||
type: 'CLOSE_WINDOW',
|
|
||||||
windowId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeWindow(windowId) {
|
|
||||||
return {
|
|
||||||
type: 'REMOVE_WINDOW',
|
|
||||||
windowId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function focusWindow(windowId) {
|
|
||||||
return {
|
|
||||||
type: 'FOCUS_WINDOW',
|
|
||||||
windowId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cloneWindow(windowId) {
|
|
||||||
return {
|
|
||||||
type: 'CLONE_WINDOW',
|
|
||||||
windowId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleMaximizeWindow(windowId) {
|
|
||||||
return {
|
|
||||||
type: 'TOGGLE_MAXIMIZE_WINDOW',
|
|
||||||
windowId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function moveWindow(windowId, xDiff, yDiff) {
|
|
||||||
return {
|
|
||||||
type: 'MOVE_WINDOW',
|
|
||||||
windowId,
|
|
||||||
xDiff,
|
|
||||||
yDiff,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resizeWindow(windowId, xDiff, yDiff) {
|
|
||||||
return {
|
|
||||||
type: 'RESIZE_WINDOW',
|
|
||||||
windowId,
|
|
||||||
xDiff,
|
|
||||||
yDiff,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function closeAllWindowTypes(windowType) {
|
|
||||||
return {
|
|
||||||
type: 'CLOSE_ALL_WINDOW_TYPE',
|
|
||||||
windowType,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hideAllWindowTypes(
|
|
||||||
windowType,
|
|
||||||
hide,
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
type: 'HIDE_ALL_WINDOW_TYPE',
|
|
||||||
windowType,
|
|
||||||
hide,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function openChatWindow() {
|
|
||||||
const width = 350;
|
|
||||||
const height = 350;
|
|
||||||
return openWindow(
|
|
||||||
'CHAT',
|
|
||||||
'',
|
|
||||||
null,
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
window.innerWidth - width - 62,
|
|
||||||
window.innerHeight - height - 64,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* query with either userId or userName
|
|
||||||
*/
|
|
||||||
export function startDm(windowId, query) {
|
|
||||||
return async (dispatch) => {
|
|
||||||
dispatch(setApiFetching(true));
|
|
||||||
const res = await requestStartDm(query);
|
|
||||||
if (typeof res === 'string') {
|
|
||||||
dispatch(pAlert(
|
|
||||||
'Direct Message Error',
|
|
||||||
res,
|
|
||||||
'error',
|
|
||||||
'OK',
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
const cid = Number(Object.keys(res)[0]);
|
|
||||||
dispatch(addChatChannel(res));
|
|
||||||
dispatch(setWindowArgs(windowId, {
|
|
||||||
chatChannel: cid,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
dispatch(setApiFetching(false));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function gotCoolDownDelta(delta) {
|
|
||||||
return {
|
|
||||||
type: 'COOLDOWN_DELTA',
|
|
||||||
delta,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setUserBlock(
|
|
||||||
userId,
|
|
||||||
userName,
|
|
||||||
block,
|
|
||||||
) {
|
|
||||||
return async (dispatch) => {
|
|
||||||
dispatch(setApiFetching(true));
|
|
||||||
const res = await requestBlock(userId, block);
|
|
||||||
if (res) {
|
|
||||||
dispatch(pAlert(
|
|
||||||
'User Block Error',
|
|
||||||
res,
|
|
||||||
'error',
|
|
||||||
'OK',
|
|
||||||
));
|
|
||||||
} else if (block) {
|
|
||||||
dispatch(blockUser(userId, userName));
|
|
||||||
} else {
|
|
||||||
dispatch(unblockUser(userId, userName));
|
|
||||||
}
|
|
||||||
dispatch(setApiFetching(false));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setBlockingDm(
|
|
||||||
block,
|
|
||||||
) {
|
|
||||||
return async (dispatch) => {
|
|
||||||
dispatch(setApiFetching(true));
|
|
||||||
const res = await requestBlockDm(block);
|
|
||||||
if (res) {
|
|
||||||
dispatch(pAlert(
|
|
||||||
'Blocking DMs Error',
|
|
||||||
res,
|
|
||||||
'error',
|
|
||||||
'OK',
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
dispatch(blockingDm(block));
|
|
||||||
}
|
|
||||||
dispatch(setApiFetching(false));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setLeaveChannel(
|
|
||||||
cid,
|
|
||||||
) {
|
|
||||||
return async (dispatch) => {
|
|
||||||
dispatch(setApiFetching(true));
|
|
||||||
const res = await requestLeaveChan(cid);
|
|
||||||
if (res) {
|
|
||||||
dispatch(pAlert(
|
|
||||||
'Leaving Channel Error',
|
|
||||||
res,
|
|
||||||
'error',
|
|
||||||
'OK',
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
dispatch(removeChatChannel(cid));
|
|
||||||
}
|
|
||||||
dispatch(setApiFetching(false));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hideContextMenu() {
|
export function hideContextMenu() {
|
||||||
return {
|
return {
|
||||||
type: 'HIDE_CONTEXT_MENU',
|
type: 'HIDE_CONTEXT_MENU',
|
||||||
|
@ -1004,3 +531,4 @@ export function urlChange() {
|
||||||
dispatch(reloadUrl());
|
dispatch(reloadUrl());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
206
src/store/actions/thunks.js
Normal file
206
src/store/actions/thunks.js
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
/*
|
||||||
|
* thunk actions
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
requestStartDm,
|
||||||
|
requestBlock,
|
||||||
|
requestBlockDm,
|
||||||
|
requestLeaveChan,
|
||||||
|
requestRankings,
|
||||||
|
requestMe,
|
||||||
|
} from './fetch';
|
||||||
|
|
||||||
|
import {
|
||||||
|
setWindowArgs,
|
||||||
|
} from './windows';
|
||||||
|
import {
|
||||||
|
addChatChannel,
|
||||||
|
pAlert,
|
||||||
|
receiveStats,
|
||||||
|
receiveMe,
|
||||||
|
blockUser,
|
||||||
|
unblockUser,
|
||||||
|
blockingDm,
|
||||||
|
removeChatChannel,
|
||||||
|
} from './index';
|
||||||
|
|
||||||
|
function setApiFetching(fetching) {
|
||||||
|
return {
|
||||||
|
type: 'SET_API_FETCHING',
|
||||||
|
fetching,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setChatFetching(fetching) {
|
||||||
|
return {
|
||||||
|
type: 'SET_CHAT_FETCHING',
|
||||||
|
fetching,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function receiveChatHistory(
|
||||||
|
cid,
|
||||||
|
history,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: 'RECEIVE_CHAT_HISTORY',
|
||||||
|
cid,
|
||||||
|
history,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* query with either userId or userName
|
||||||
|
*/
|
||||||
|
export function startDm(windowId, query) {
|
||||||
|
return async (dispatch) => {
|
||||||
|
dispatch(setApiFetching(true));
|
||||||
|
const res = await requestStartDm(query);
|
||||||
|
if (typeof res === 'string') {
|
||||||
|
dispatch(pAlert(
|
||||||
|
'Direct Message Error',
|
||||||
|
res,
|
||||||
|
'error',
|
||||||
|
'OK',
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
const cid = Number(Object.keys(res)[0]);
|
||||||
|
dispatch(addChatChannel(res));
|
||||||
|
dispatch(setWindowArgs(windowId, {
|
||||||
|
chatChannel: cid,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
dispatch(setApiFetching(false));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchStats() {
|
||||||
|
return async (dispatch) => {
|
||||||
|
const rankings = await requestRankings();
|
||||||
|
if (!rankings.errors) {
|
||||||
|
dispatch(receiveStats(rankings));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchMe() {
|
||||||
|
return async (dispatch) => {
|
||||||
|
const me = await requestMe();
|
||||||
|
if (!me.errors) {
|
||||||
|
dispatch(receiveMe(me));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchChatMessages(
|
||||||
|
cid,
|
||||||
|
) {
|
||||||
|
return async (dispatch) => {
|
||||||
|
dispatch(setChatFetching(true));
|
||||||
|
const response = await fetch(`api/chathistory?cid=${cid}&limit=50`, {
|
||||||
|
credentials: 'include',
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* timeout in order to not spam api requests and get rate limited
|
||||||
|
*/
|
||||||
|
if (response.ok) {
|
||||||
|
setTimeout(() => { dispatch(setChatFetching(false)); }, 500);
|
||||||
|
const { history } = await response.json();
|
||||||
|
dispatch(receiveChatHistory(cid, history));
|
||||||
|
} else {
|
||||||
|
setTimeout(() => { dispatch(setChatFetching(false)); }, 5000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setUserBlock(
|
||||||
|
userId,
|
||||||
|
userName,
|
||||||
|
block,
|
||||||
|
) {
|
||||||
|
return async (dispatch) => {
|
||||||
|
dispatch(setApiFetching(true));
|
||||||
|
const res = await requestBlock(userId, block);
|
||||||
|
if (res) {
|
||||||
|
dispatch(pAlert(
|
||||||
|
'User Block Error',
|
||||||
|
res,
|
||||||
|
'error',
|
||||||
|
'OK',
|
||||||
|
));
|
||||||
|
} else if (block) {
|
||||||
|
dispatch(blockUser(userId, userName));
|
||||||
|
} else {
|
||||||
|
dispatch(unblockUser(userId, userName));
|
||||||
|
}
|
||||||
|
dispatch(setApiFetching(false));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setBlockingDm(
|
||||||
|
block,
|
||||||
|
) {
|
||||||
|
return async (dispatch) => {
|
||||||
|
dispatch(setApiFetching(true));
|
||||||
|
const res = await requestBlockDm(block);
|
||||||
|
if (res) {
|
||||||
|
dispatch(pAlert(
|
||||||
|
'Blocking DMs Error',
|
||||||
|
res,
|
||||||
|
'error',
|
||||||
|
'OK',
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
dispatch(blockingDm(block));
|
||||||
|
}
|
||||||
|
dispatch(setApiFetching(false));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setLeaveChannel(
|
||||||
|
cid,
|
||||||
|
) {
|
||||||
|
return async (dispatch) => {
|
||||||
|
dispatch(setApiFetching(true));
|
||||||
|
const res = await requestLeaveChan(cid);
|
||||||
|
if (res) {
|
||||||
|
dispatch(pAlert(
|
||||||
|
'Leaving Channel Error',
|
||||||
|
res,
|
||||||
|
'error',
|
||||||
|
'OK',
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
dispatch(removeChatChannel(cid));
|
||||||
|
}
|
||||||
|
dispatch(setApiFetching(false));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setNotification(notification) {
|
||||||
|
return {
|
||||||
|
type: 'SET_NOTIFICATION',
|
||||||
|
notification,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsetNotification() {
|
||||||
|
return {
|
||||||
|
type: 'UNSET_NOTIFICATION',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastNotify = null;
|
||||||
|
export function notify(notification) {
|
||||||
|
return (dispatch) => {
|
||||||
|
dispatch(setNotification(notification));
|
||||||
|
if (lastNotify) {
|
||||||
|
clearTimeout(lastNotify);
|
||||||
|
lastNotify = null;
|
||||||
|
}
|
||||||
|
lastNotify = setTimeout(() => {
|
||||||
|
dispatch(unsetNotification());
|
||||||
|
}, 1500);
|
||||||
|
};
|
||||||
|
}
|
238
src/store/actions/windows.js
Normal file
238
src/store/actions/windows.js
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
* Actions that are exclusively used by windows
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { t } from 'ttag';
|
||||||
|
|
||||||
|
export function openWindow(
|
||||||
|
windowType,
|
||||||
|
title = '',
|
||||||
|
args = null,
|
||||||
|
fullscreen = false,
|
||||||
|
cloneable = true,
|
||||||
|
xPos = null,
|
||||||
|
yPos = null,
|
||||||
|
width = null,
|
||||||
|
height = null,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: 'OPEN_WINDOW',
|
||||||
|
windowType,
|
||||||
|
title,
|
||||||
|
args,
|
||||||
|
fullscreen,
|
||||||
|
cloneable,
|
||||||
|
xPos,
|
||||||
|
yPos,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setWindowArgs(
|
||||||
|
windowId,
|
||||||
|
args,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: 'SET_WINDOW_ARGS',
|
||||||
|
windowId,
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function showFullscreenWindow(modalType, title) {
|
||||||
|
return openWindow(
|
||||||
|
modalType,
|
||||||
|
title,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeFullscreenWindows() {
|
||||||
|
return {
|
||||||
|
type: 'CLOSE_FULLSCREEN_WINDOWS',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showSettingsModal() {
|
||||||
|
return showFullscreenWindow(
|
||||||
|
'SETTINGS',
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showUserAreaModal() {
|
||||||
|
return showFullscreenWindow(
|
||||||
|
'USERAREA',
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changeWindowType(
|
||||||
|
windowId,
|
||||||
|
windowType,
|
||||||
|
title = '',
|
||||||
|
args = null,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: 'CHANGE_WINDOW_TYPE',
|
||||||
|
windowId,
|
||||||
|
windowType,
|
||||||
|
title,
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setWindowTitle(windowId, title) {
|
||||||
|
return {
|
||||||
|
type: 'SET_WINDOW_TITLE',
|
||||||
|
windowId,
|
||||||
|
title,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showRegisterModal() {
|
||||||
|
return showFullscreenWindow(
|
||||||
|
'REGISTER',
|
||||||
|
t`Register New Account`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showForgotPasswordModal() {
|
||||||
|
return showFullscreenWindow(
|
||||||
|
'FORGOT_PASSWORD',
|
||||||
|
t`Restore my Password`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showHelpModal() {
|
||||||
|
return showFullscreenWindow(
|
||||||
|
'HELP',
|
||||||
|
t`Welcome to PixelPlanet.fun`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function showArchiveModal() {
|
||||||
|
return showFullscreenWindow(
|
||||||
|
'ARCHIVE',
|
||||||
|
t`Look at past Canvases`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showCanvasSelectionModal() {
|
||||||
|
return showFullscreenWindow(
|
||||||
|
'CANVAS_SELECTION',
|
||||||
|
'',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addToChatInputMessage(windowId, msg, focus = true) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const args = getState().windows.args[windowId];
|
||||||
|
let inputMessage = args && args.inputMessage;
|
||||||
|
if (!inputMessage) {
|
||||||
|
inputMessage = '';
|
||||||
|
} else if (inputMessage.slice(-1) !== ' ') {
|
||||||
|
inputMessage += ' ';
|
||||||
|
}
|
||||||
|
inputMessage += msg;
|
||||||
|
|
||||||
|
dispatch(setWindowArgs(windowId, {
|
||||||
|
inputMessage,
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (focus) {
|
||||||
|
const inputElem = document.getElementById(`chtipt-${windowId}`);
|
||||||
|
if (inputElem) {
|
||||||
|
inputElem.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeWindow(windowId) {
|
||||||
|
return {
|
||||||
|
type: 'CLOSE_WINDOW',
|
||||||
|
windowId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removeWindow(windowId) {
|
||||||
|
return {
|
||||||
|
type: 'REMOVE_WINDOW',
|
||||||
|
windowId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function focusWindow(windowId) {
|
||||||
|
return {
|
||||||
|
type: 'FOCUS_WINDOW',
|
||||||
|
windowId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cloneWindow(windowId) {
|
||||||
|
return {
|
||||||
|
type: 'CLONE_WINDOW',
|
||||||
|
windowId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toggleMaximizeWindow(windowId) {
|
||||||
|
return {
|
||||||
|
type: 'TOGGLE_MAXIMIZE_WINDOW',
|
||||||
|
windowId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function moveWindow(windowId, xDiff, yDiff) {
|
||||||
|
return {
|
||||||
|
type: 'MOVE_WINDOW',
|
||||||
|
windowId,
|
||||||
|
xDiff,
|
||||||
|
yDiff,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resizeWindow(windowId, xDiff, yDiff) {
|
||||||
|
return {
|
||||||
|
type: 'RESIZE_WINDOW',
|
||||||
|
windowId,
|
||||||
|
xDiff,
|
||||||
|
yDiff,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function closeAllWindowTypes(windowType) {
|
||||||
|
return {
|
||||||
|
type: 'CLOSE_ALL_WINDOW_TYPE',
|
||||||
|
windowType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hideAllWindowTypes(
|
||||||
|
windowType,
|
||||||
|
hide,
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
type: 'HIDE_ALL_WINDOW_TYPE',
|
||||||
|
windowType,
|
||||||
|
hide,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function openChatWindow() {
|
||||||
|
const width = 350;
|
||||||
|
const height = 350;
|
||||||
|
return openWindow(
|
||||||
|
'CHAT',
|
||||||
|
'',
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
window.innerWidth - width - 62,
|
||||||
|
window.innerHeight - height - 64,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,7 +1,15 @@
|
||||||
import { applyMiddleware, createStore, compose } from 'redux';
|
/*
|
||||||
|
* redux store
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
|
import {
|
||||||
|
applyMiddleware, createStore, compose, combineReducers,
|
||||||
|
} from 'redux';
|
||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
import { persistStore, persistCombineReducers } from 'redux-persist';
|
import { persistStore, persistReducer } from 'redux-persist';
|
||||||
import localForage from 'localforage';
|
import storage from 'redux-persist/lib/storage';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* reducers
|
* reducers
|
||||||
|
@ -29,12 +37,23 @@ import array from './middleware/array';
|
||||||
import promise from './middleware/promise';
|
import promise from './middleware/promise';
|
||||||
import notifications from './middleware/notifications';
|
import notifications from './middleware/notifications';
|
||||||
import title from './middleware/title';
|
import title from './middleware/title';
|
||||||
import placePixelControl from './middleware/placePixelControl';
|
// import placePixelControl from './middleware/placePixelControl';
|
||||||
import extensions from './middleware/extensions';
|
import extensions from './middleware/extensions';
|
||||||
|
|
||||||
const reducers = persistCombineReducers({
|
const CURRENT_VERSION = 3;
|
||||||
|
|
||||||
|
const reducers = persistReducer({
|
||||||
key: 'primary',
|
key: 'primary',
|
||||||
storage: localForage,
|
storage,
|
||||||
|
version: CURRENT_VERSION,
|
||||||
|
migrate: (state, version) => {
|
||||||
|
if (version !== CURRENT_VERSION) {
|
||||||
|
console.log('Newer version run, resetting store.');
|
||||||
|
return Promise.resolve({});
|
||||||
|
}
|
||||||
|
console.log(`Store version: ${version}`);
|
||||||
|
return Promise.resolve(state);
|
||||||
|
},
|
||||||
blacklist: [
|
blacklist: [
|
||||||
'user',
|
'user',
|
||||||
'canvas',
|
'canvas',
|
||||||
|
@ -43,7 +62,7 @@ const reducers = persistCombineReducers({
|
||||||
'contextMenu',
|
'contextMenu',
|
||||||
'fetching',
|
'fetching',
|
||||||
],
|
],
|
||||||
}, {
|
}, combineReducers({
|
||||||
audio,
|
audio,
|
||||||
canvas,
|
canvas,
|
||||||
gui,
|
gui,
|
||||||
|
@ -55,7 +74,7 @@ const reducers = persistCombineReducers({
|
||||||
contextMenu,
|
contextMenu,
|
||||||
chatRead,
|
chatRead,
|
||||||
fetching,
|
fetching,
|
||||||
});
|
}));
|
||||||
|
|
||||||
const store = createStore(
|
const store = createStore(
|
||||||
reducers,
|
reducers,
|
||||||
|
@ -70,7 +89,7 @@ const store = createStore(
|
||||||
title,
|
title,
|
||||||
socketClientHook,
|
socketClientHook,
|
||||||
rendererHook,
|
rendererHook,
|
||||||
placePixelControl,
|
// placePixelControl,
|
||||||
extensions,
|
extensions,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -68,30 +68,6 @@ export default (store) => (next) => (action) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'PIXEL_WAIT': {
|
|
||||||
/*
|
|
||||||
* TODO refactor other sounds also like this one
|
|
||||||
* i.e. gain sould ramp to 0, do oscillator first
|
|
||||||
*/
|
|
||||||
const oscillatorNode = context.createOscillator();
|
|
||||||
const gainNode = context.createGain();
|
|
||||||
const { currentTime } = context;
|
|
||||||
|
|
||||||
oscillatorNode.type = 'sine';
|
|
||||||
oscillatorNode.start(currentTime);
|
|
||||||
oscillatorNode.frequency.setValueAtTime(1479.98, currentTime);
|
|
||||||
oscillatorNode.frequency.exponentialRampToValueAtTime(
|
|
||||||
493.88,
|
|
||||||
currentTime + 0.01,
|
|
||||||
);
|
|
||||||
oscillatorNode.stop(currentTime + 0.1);
|
|
||||||
gainNode.gain.setValueAtTime(0.5, currentTime);
|
|
||||||
gainNode.gain.setTargetAtTime(0, currentTime, 0.1);
|
|
||||||
oscillatorNode.connect(gainNode);
|
|
||||||
gainNode.connect(context.destination);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'ALERT': {
|
case 'ALERT': {
|
||||||
const oscillatorNode = context.createOscillator();
|
const oscillatorNode = context.createOscillator();
|
||||||
const gainNode = context.createGain();
|
const gainNode = context.createGain();
|
||||||
|
@ -143,40 +119,62 @@ export default (store) => (next) => (action) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'PLACED_PIXELS': {
|
case 'RECEIVE_PIXEL_RETURN': {
|
||||||
const { palette, selectedColor: color } = state.canvas;
|
switch (action.retCode) {
|
||||||
const colorsAmount = palette.colors.length;
|
case 0: {
|
||||||
|
// successfully placed pixel
|
||||||
|
const { palette, selectedColor: color } = state.canvas;
|
||||||
|
const colorsAmount = palette.colors.length;
|
||||||
|
|
||||||
const clrFreq = 100 + Math.log(color / colorsAmount + 1) * 300;
|
const clrFreq = 100 + Math.log(color / colorsAmount + 1) * 300;
|
||||||
const oscillatorNode = context.createOscillator();
|
const oscillatorNode = context.createOscillator();
|
||||||
const gainNode = context.createGain();
|
const gainNode = context.createGain();
|
||||||
const { currentTime } = context;
|
const { currentTime } = context;
|
||||||
|
|
||||||
oscillatorNode.type = 'sine';
|
oscillatorNode.type = 'sine';
|
||||||
oscillatorNode.frequency.setValueAtTime(clrFreq, currentTime);
|
oscillatorNode.start(currentTime);
|
||||||
oscillatorNode.frequency.exponentialRampToValueAtTime(
|
oscillatorNode.frequency.setValueAtTime(clrFreq, currentTime);
|
||||||
1400,
|
oscillatorNode.frequency.exponentialRampToValueAtTime(
|
||||||
currentTime + 0.2,
|
1400,
|
||||||
);
|
currentTime + 0.2,
|
||||||
|
);
|
||||||
|
oscillatorNode.stop(currentTime + 0.1);
|
||||||
|
gainNode.gain.setValueAtTime(0.5, currentTime);
|
||||||
|
gainNode.gain.setTargetAtTime(0, currentTime, 0.1);
|
||||||
|
oscillatorNode.connect(gainNode);
|
||||||
|
gainNode.connect(context.destination);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 9: {
|
||||||
|
// pixelstack used up
|
||||||
|
const oscillatorNode = context.createOscillator();
|
||||||
|
const gainNode = context.createGain();
|
||||||
|
const { currentTime } = context;
|
||||||
|
|
||||||
gainNode.gain.setValueAtTime(0.5, currentTime);
|
oscillatorNode.type = 'sine';
|
||||||
gainNode.gain.exponentialRampToValueAtTime(
|
oscillatorNode.start(currentTime);
|
||||||
0.2,
|
oscillatorNode.frequency.setValueAtTime(1479.98, currentTime);
|
||||||
currentTime + 0.1,
|
oscillatorNode.frequency.exponentialRampToValueAtTime(
|
||||||
);
|
493.88,
|
||||||
|
currentTime + 0.01,
|
||||||
oscillatorNode.connect(gainNode);
|
);
|
||||||
gainNode.connect(context.destination);
|
oscillatorNode.stop(currentTime + 0.1);
|
||||||
|
gainNode.gain.setValueAtTime(0.5, currentTime);
|
||||||
oscillatorNode.start();
|
gainNode.gain.setTargetAtTime(0, currentTime, 0.1);
|
||||||
oscillatorNode.stop(currentTime + 0.1);
|
oscillatorNode.connect(gainNode);
|
||||||
|
gainNode.connect(context.destination);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'COOLDOWN_END': {
|
case 'COOLDOWN_END': {
|
||||||
// do not play sound if last cooldown end was <5s ago
|
// do not play sound if last cooldown end was <5s ago
|
||||||
const { lastCoolDownEnd } = state.user;
|
const { lastCoolDownEnd } = state.user;
|
||||||
if (lastCoolDownEnd && lastCoolDownEnd.getTime() + 5000 > Date.now()) {
|
if (lastCoolDownEnd && lastCoolDownEnd + 5000 > Date.now()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
* Notifications
|
* Notifications
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
import { t } from 'ttag';
|
||||||
|
|
||||||
export default (store) => (next) => (action) => {
|
export default (store) => (next) => (action) => {
|
||||||
try {
|
try {
|
||||||
if (!document.hasFocus()) {
|
if (!document.hasFocus()) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'RECEIVE_ME':
|
case 'RECEIVE_ME': {
|
||||||
case 'PLACED_PIXELS': {
|
|
||||||
if (window.Notification
|
if (window.Notification
|
||||||
&& Notification.permission !== 'granted'
|
&& Notification.permission !== 'granted'
|
||||||
&& Notification.permission !== 'denied'
|
&& Notification.permission !== 'denied'
|
||||||
|
@ -25,17 +24,17 @@ export default (store) => (next) => (action) => {
|
||||||
// do not notify if last cooldown end was <15s ago
|
// do not notify if last cooldown end was <15s ago
|
||||||
const { lastCoolDownEnd } = state.user;
|
const { lastCoolDownEnd } = state.user;
|
||||||
if (lastCoolDownEnd
|
if (lastCoolDownEnd
|
||||||
&& lastCoolDownEnd.getTime() + 15000 > Date.now()) {
|
&& lastCoolDownEnd + 15000 > Date.now()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.Notification && Notification.permission === 'granted') {
|
if (window.Notification && Notification.permission === 'granted') {
|
||||||
// eslint-disable-next-line no-new
|
// eslint-disable-next-line no-new
|
||||||
new Notification('Your next pixels are ready', {
|
new Notification(t`Your next pixels are ready`, {
|
||||||
icon: '/tile.png',
|
icon: '/tile.png',
|
||||||
silent: false,
|
silent: false,
|
||||||
vibrate: [200, 100],
|
vibrate: [200, 100],
|
||||||
body: 'You can now place more on pixelplanet.fun :)',
|
body: t`You can now place more on pixelplanet.fun :)`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -52,11 +51,11 @@ export default (store) => (next) => (action) => {
|
||||||
|
|
||||||
if (window.Notification && Notification.permission === 'granted') {
|
if (window.Notification && Notification.permission === 'granted') {
|
||||||
// eslint-disable-next-line no-new
|
// eslint-disable-next-line no-new
|
||||||
new Notification(`${name} mentioned you`, {
|
new Notification(`${name} ${t`mentioned you`}`, {
|
||||||
icon: '/tile.png',
|
icon: '/tile.png',
|
||||||
silent: false,
|
silent: false,
|
||||||
vibrate: [200, 100],
|
vibrate: [200, 100],
|
||||||
body: 'You have new messages in chat',
|
body: t`You have new messages in chat`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3,17 +3,36 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { requestFromQueue } from '../../ui/placePixel';
|
import { getRenderer } from '../../ui/renderer';
|
||||||
|
import { receivePixelReturn } from '../../ui/placePixel';
|
||||||
|
|
||||||
export default (store) => (next) => (action) => {
|
export default (store) => (next) => (action) => {
|
||||||
|
const ret = next(action);
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'CLOSE_ALERT': {
|
case 'RECEIVE_PIXEL_RETURN': {
|
||||||
requestFromQueue(store);
|
const renderer = getRenderer();
|
||||||
|
const {
|
||||||
|
retCode,
|
||||||
|
wait,
|
||||||
|
coolDownSeconds,
|
||||||
|
pxlCnt,
|
||||||
|
rankedPxlCnt,
|
||||||
|
} = action;
|
||||||
|
receivePixelReturn(
|
||||||
|
store,
|
||||||
|
renderer,
|
||||||
|
retCode,
|
||||||
|
wait,
|
||||||
|
coolDownSeconds,
|
||||||
|
pxlCnt,
|
||||||
|
rankedPxlCnt,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
return next(action);
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
|
@ -95,7 +95,7 @@ export default (store) => (next) => (action) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'TOGGLE_GRID':
|
case 'TOGGLE_GRID':
|
||||||
case 'SET_REQUESTING_PIXEL': {
|
case 'ALLOW_SETTING_PIXEL': {
|
||||||
const renderer = getRenderer();
|
const renderer = getRenderer();
|
||||||
renderer.forceNextSubrender = true;
|
renderer.forceNextSubrender = true;
|
||||||
break;
|
break;
|
||||||
|
@ -108,30 +108,21 @@ export default (store) => (next) => (action) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'UPDATE_PIXEL': {
|
|
||||||
const {
|
|
||||||
i,
|
|
||||||
j,
|
|
||||||
offset,
|
|
||||||
color,
|
|
||||||
notify,
|
|
||||||
} = action;
|
|
||||||
const renderer = getRenderer();
|
|
||||||
renderer.renderPixel(i, j, offset, color, notify);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'SET_VIEW_COORDINATES': {
|
case 'SET_VIEW_COORDINATES': {
|
||||||
const renderer = getRenderer();
|
const renderer = getRenderer();
|
||||||
renderer.updateView(state);
|
renderer.updateView(state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'COOLDOWN_DELTA': {
|
case 'RECEIVE_PIXEL_RETURN': {
|
||||||
const { delta } = action;
|
|
||||||
const renderer = getRenderer();
|
const renderer = getRenderer();
|
||||||
if (renderer && renderer.controls && renderer.controls.gotCoolDownDelta) {
|
renderer.forceNextSubrender = true;
|
||||||
renderer.controls.gotCoolDownDelta(delta * -1);
|
const { coolDownSeconds } = action;
|
||||||
|
if (coolDownSeconds < 0
|
||||||
|
&& renderer && renderer.controls
|
||||||
|
&& renderer.controls.gotCoolDownDelta
|
||||||
|
) {
|
||||||
|
renderer.controls.gotCoolDownDelta(coolDownSeconds * -1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,16 @@ export default function ranks(
|
||||||
action,
|
action,
|
||||||
) {
|
) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'PLACED_PIXELS': {
|
case 'RECEIVE_PIXEL_RETURN': {
|
||||||
|
const {
|
||||||
|
rankedPxlCnt,
|
||||||
|
} = action;
|
||||||
|
if (!rankedPxlCnt) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
let { totalPixels, dailyTotalPixels } = state;
|
let { totalPixels, dailyTotalPixels } = state;
|
||||||
const { amount } = action;
|
totalPixels += rankedPxlCnt;
|
||||||
totalPixels += amount;
|
dailyTotalPixels += rankedPxlCnt;
|
||||||
dailyTotalPixels += amount;
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
totalPixels,
|
totalPixels,
|
||||||
|
|
|
@ -4,7 +4,7 @@ const initialState = {
|
||||||
wait: null,
|
wait: null,
|
||||||
coolDown: null, // ms
|
coolDown: null, // ms
|
||||||
lastCoolDownEnd: null,
|
lastCoolDownEnd: null,
|
||||||
requestingPixel: true,
|
allowSettingPixel: true,
|
||||||
// messages are sent by api/me, like not_verified status
|
// messages are sent by api/me, like not_verified status
|
||||||
messages: [],
|
messages: [],
|
||||||
mailreg: false,
|
mailreg: false,
|
||||||
|
@ -35,34 +35,34 @@ export default function user(
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
coolDown: null,
|
coolDown: null,
|
||||||
lastCoolDownEnd: new Date(),
|
lastCoolDownEnd: Date().now(),
|
||||||
wait: null,
|
wait: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'SET_REQUESTING_PIXEL': {
|
case 'ALLOW_SETTING_PIXEL': {
|
||||||
const { requestingPixel } = action;
|
const { allowSettingPixel } = action;
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
requestingPixel,
|
allowSettingPixel,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'SET_WAIT': {
|
case 'RECEIVE_PIXEL_RETURN': {
|
||||||
const { wait: duration } = action;
|
const {
|
||||||
const wait = duration
|
wait: duration,
|
||||||
? new Date(Date.now() + duration)
|
} = action;
|
||||||
: null;
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
wait,
|
wait: (duration) ? Date.now() + duration : state.wait,
|
||||||
|
allowSettingPixel: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'RECEIVE_COOLDOWN': {
|
case 'RECEIVE_COOLDOWN': {
|
||||||
const { wait: duration } = action;
|
const { wait: duration } = action;
|
||||||
const wait = duration
|
const wait = duration
|
||||||
? new Date(Date.now() + duration)
|
? Date.now() + duration
|
||||||
: null;
|
: null;
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
|
@ -73,13 +73,20 @@ function clampPos(prefXPos, prefYPos, width, height) {
|
||||||
*/
|
*/
|
||||||
function sortWindows(newState, force = false) {
|
function sortWindows(newState, force = false) {
|
||||||
if (newState.zMax >= MAX_AMOUNT_WINDOWS * 0.5 || force) {
|
if (newState.zMax >= MAX_AMOUNT_WINDOWS * 0.5 || force) {
|
||||||
const orderedZ = newState.windows.map((win) => win.z)
|
const positions = { ...newState.positions };
|
||||||
|
const ids = Object.keys(positions);
|
||||||
|
const orderedZ = ids
|
||||||
|
.map((id) => positions[id].z)
|
||||||
.sort((a, b) => !b || (a && a >= b));
|
.sort((a, b) => !b || (a && a >= b));
|
||||||
newState.windows = newState.windows.map((win) => ({
|
for (let i = 0; i < ids.length; i += 1) {
|
||||||
...win,
|
const id = ids[i];
|
||||||
z: orderedZ.indexOf(win.z),
|
positions[id] = {
|
||||||
}));
|
...positions[id],
|
||||||
|
z: orderedZ.indexOf(positions[id].z),
|
||||||
|
};
|
||||||
|
}
|
||||||
newState.zMax = orderedZ.length - 1;
|
newState.zMax = orderedZ.length - 1;
|
||||||
|
newState.positions = positions;
|
||||||
}
|
}
|
||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
@ -87,8 +94,6 @@ function sortWindows(newState, force = false) {
|
||||||
const initialState = {
|
const initialState = {
|
||||||
// if windows get shown, false on small screens
|
// if windows get shown, false on small screens
|
||||||
showWindows: window.innerWidth > SCREEN_WIDTH_THRESHOLD,
|
showWindows: window.innerWidth > SCREEN_WIDTH_THRESHOLD,
|
||||||
// if at least one window is in fullscreen
|
|
||||||
someFullscreen: false,
|
|
||||||
// highest zIndex of window
|
// highest zIndex of window
|
||||||
zMax: 0,
|
zMax: 0,
|
||||||
// [
|
// [
|
||||||
|
@ -97,20 +102,25 @@ const initialState = {
|
||||||
// open: boolean,
|
// open: boolean,
|
||||||
// hidden: boolean,
|
// hidden: boolean,
|
||||||
// fullscreen: boolean,
|
// fullscreen: boolean,
|
||||||
// z: number,
|
|
||||||
// windowType: string,
|
// windowType: string,
|
||||||
// title: string,
|
// title: string,
|
||||||
// title that is additionally shown to the window-type-title
|
// title that is additionally shown to the window-type-title
|
||||||
// width: number,
|
|
||||||
// height: number,
|
|
||||||
// xPos: percentage,
|
|
||||||
// yPos: percentage,
|
|
||||||
// cloneable: boolean,
|
// cloneable: boolean,
|
||||||
// },
|
// },
|
||||||
// ]
|
// ]
|
||||||
windows: [],
|
windows: [],
|
||||||
// {
|
// {
|
||||||
// windowId: {
|
// windowId: {
|
||||||
|
// width: number,
|
||||||
|
// height: number,
|
||||||
|
// xPos: percentage,
|
||||||
|
// yPos: percentage,
|
||||||
|
// z: number,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
positions: {},
|
||||||
|
// {
|
||||||
|
// windowId: {
|
||||||
// ...
|
// ...
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
@ -152,39 +162,38 @@ export default function windows(
|
||||||
}
|
}
|
||||||
const windowId = generateWindowId(state);
|
const windowId = generateWindowId(state);
|
||||||
const newZMax = state.zMax + 1;
|
const newZMax = state.zMax + 1;
|
||||||
const newWindows = [
|
|
||||||
...state.windows,
|
|
||||||
{
|
|
||||||
windowId,
|
|
||||||
windowType,
|
|
||||||
open: true,
|
|
||||||
hidden: false,
|
|
||||||
fullscreen,
|
|
||||||
z: newZMax,
|
|
||||||
title,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
xPos,
|
|
||||||
yPos,
|
|
||||||
cloneable,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const someFullscreen = newWindows.some(
|
|
||||||
(win) => win.fullscreen && !win.hidden,
|
|
||||||
);
|
|
||||||
|
|
||||||
return sortWindows({
|
return sortWindows({
|
||||||
...state,
|
...state,
|
||||||
someFullscreen,
|
|
||||||
zMax: newZMax,
|
zMax: newZMax,
|
||||||
windows: newWindows,
|
windows: [
|
||||||
|
...state.windows,
|
||||||
|
{
|
||||||
|
windowId,
|
||||||
|
windowType,
|
||||||
|
open: true,
|
||||||
|
hidden: false,
|
||||||
|
fullscreen,
|
||||||
|
title,
|
||||||
|
cloneable,
|
||||||
|
},
|
||||||
|
],
|
||||||
args: {
|
args: {
|
||||||
...state.args,
|
...state.args,
|
||||||
[windowId]: {
|
[windowId]: {
|
||||||
...args,
|
...args,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
positions: {
|
||||||
|
...state.positions,
|
||||||
|
[windowId]: {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
xPos,
|
||||||
|
yPos,
|
||||||
|
z: newZMax,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,12 +202,15 @@ export default function windows(
|
||||||
windowId,
|
windowId,
|
||||||
} = action;
|
} = action;
|
||||||
const args = { ...state.args };
|
const args = { ...state.args };
|
||||||
|
const positions = { ...state.positions };
|
||||||
delete args[windowId];
|
delete args[windowId];
|
||||||
|
delete positions[windowId];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
windows: state.windows.filter((win) => win.windowId !== windowId),
|
windows: state.windows.filter((win) => win.windowId !== windowId),
|
||||||
args,
|
args,
|
||||||
|
positions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,13 +227,8 @@ export default function windows(
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const someFullscreen = newWindows.some(
|
|
||||||
(win) => win.fullscreen && !win.hidden,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
someFullscreen,
|
|
||||||
windows: newWindows,
|
windows: newWindows,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -238,13 +245,8 @@ export default function windows(
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const someFullscreen = newWindows.some(
|
|
||||||
(win) => win.fullscreen && !win.hidden,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
someFullscreen,
|
|
||||||
windows: newWindows,
|
windows: newWindows,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -272,6 +274,7 @@ export default function windows(
|
||||||
windowId,
|
windowId,
|
||||||
} = action;
|
} = action;
|
||||||
const win = state.windows.find((w) => w.windowId === windowId);
|
const win = state.windows.find((w) => w.windowId === windowId);
|
||||||
|
const position = state.positions[windowId];
|
||||||
const newWindowId = generateWindowId(state);
|
const newWindowId = generateWindowId(state);
|
||||||
const newZMax = state.zMax + 1;
|
const newZMax = state.zMax + 1;
|
||||||
const {
|
const {
|
||||||
|
@ -286,9 +289,6 @@ export default function windows(
|
||||||
{
|
{
|
||||||
...win,
|
...win,
|
||||||
windowId: newWindowId,
|
windowId: newWindowId,
|
||||||
xPos: Math.min(win.xPos + 15, width - SCREEN_MARGIN_EW),
|
|
||||||
yPos: Math.min(win.yPos + 15, height - SCREEN_MARGIN_S),
|
|
||||||
z: newZMax,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
args: {
|
args: {
|
||||||
|
@ -297,6 +297,15 @@ export default function windows(
|
||||||
...state.args[windowId],
|
...state.args[windowId],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
positions: {
|
||||||
|
...state.positions,
|
||||||
|
[newWindowId]: {
|
||||||
|
...position,
|
||||||
|
xPos: Math.min(position.xPos + 15, width - SCREEN_MARGIN_EW),
|
||||||
|
yPos: Math.min(position.yPos + 15, height - SCREEN_MARGIN_S),
|
||||||
|
z: newZMax,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,13 +330,8 @@ export default function windows(
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const someFullscreen = newWindows.some(
|
|
||||||
(win) => win.fullscreen && !win.hidden,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
someFullscreen,
|
|
||||||
args,
|
args,
|
||||||
windows: newWindows,
|
windows: newWindows,
|
||||||
};
|
};
|
||||||
|
@ -338,29 +342,22 @@ export default function windows(
|
||||||
windowId,
|
windowId,
|
||||||
} = action;
|
} = action;
|
||||||
const {
|
const {
|
||||||
windows: oldWindows, zMax,
|
zMax,
|
||||||
} = state;
|
} = state;
|
||||||
|
const { z } = state.positions[windowId];
|
||||||
const newWindows = [];
|
if (z === zMax) {
|
||||||
|
return state;
|
||||||
for (let i = 0; i < oldWindows.length; i += 1) {
|
|
||||||
const win = oldWindows[i];
|
|
||||||
if (win.windowId !== windowId) {
|
|
||||||
newWindows.push(win);
|
|
||||||
} else {
|
|
||||||
if (win.z === zMax) {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
newWindows.push({
|
|
||||||
...win,
|
|
||||||
z: zMax + 1,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return sortWindows({
|
return sortWindows({
|
||||||
...state,
|
...state,
|
||||||
zMax: zMax + 1,
|
zMax: zMax + 1,
|
||||||
windows: newWindows,
|
positions: {
|
||||||
|
...state.positions,
|
||||||
|
[windowId]: {
|
||||||
|
...state.positions[windowId],
|
||||||
|
z: zMax + 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,13 +376,8 @@ export default function windows(
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const someFullscreen = newWindows.some(
|
|
||||||
(win) => win.fullscreen && !win.hidden,
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
someFullscreen,
|
|
||||||
windows: newWindows,
|
windows: newWindows,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -403,7 +395,6 @@ export default function windows(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
someFullscreen: false,
|
|
||||||
windows: newWindows,
|
windows: newWindows,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -414,23 +405,23 @@ export default function windows(
|
||||||
xDiff,
|
xDiff,
|
||||||
yDiff,
|
yDiff,
|
||||||
} = action;
|
} = action;
|
||||||
const newWindows = state.windows.map((win) => {
|
let {
|
||||||
if (win.windowId !== windowId) return win;
|
xPos, yPos,
|
||||||
const [xPos, yPos] = clampPos(
|
} = state.positions[windowId];
|
||||||
win.xPos + xDiff,
|
const {
|
||||||
win.yPos + yDiff,
|
width, height,
|
||||||
win.width,
|
} = state.positions[windowId];
|
||||||
win.height,
|
[xPos, yPos] = clampPos(xPos + xDiff, yPos + yDiff, width, height);
|
||||||
);
|
|
||||||
return {
|
|
||||||
...win,
|
|
||||||
xPos,
|
|
||||||
yPos,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
windows: newWindows,
|
positions: {
|
||||||
|
...state.positions,
|
||||||
|
[windowId]: {
|
||||||
|
...state.positions[windowId],
|
||||||
|
xPos,
|
||||||
|
yPos,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,22 +431,18 @@ export default function windows(
|
||||||
xDiff,
|
xDiff,
|
||||||
yDiff,
|
yDiff,
|
||||||
} = action;
|
} = action;
|
||||||
const newWindows = state.windows.map((win) => {
|
let { width, height } = state.positions[windowId];
|
||||||
if (win.windowId !== windowId) return win;
|
[width, height] = clampSize(width + xDiff, height + yDiff, false);
|
||||||
const [width, height] = clampSize(
|
|
||||||
win.width + xDiff,
|
|
||||||
win.height + yDiff,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
...win,
|
|
||||||
width: Math.max(width, SCREEN_MARGIN_EW - win.xPos),
|
|
||||||
height,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
windows: newWindows,
|
positions: {
|
||||||
|
...state.positions,
|
||||||
|
[windowId]: {
|
||||||
|
...state.positions[windowId],
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,16 +453,17 @@ export default function windows(
|
||||||
innerHeight: height,
|
innerHeight: height,
|
||||||
} = window;
|
} = window;
|
||||||
|
|
||||||
let { windows: newWindows, args, someFullscreen } = state;
|
let { windows: newWindows, args, positions } = state;
|
||||||
const showWindows = width > SCREEN_WIDTH_THRESHOLD;
|
const showWindows = width > SCREEN_WIDTH_THRESHOLD;
|
||||||
|
|
||||||
if (action.type === 'RECEIVE_ME') {
|
if (action.type === 'RECEIVE_ME') {
|
||||||
if (state.modal) {
|
if (!showWindows) {
|
||||||
// reset if out of date
|
// reset on phones on every refresh
|
||||||
return initialState;
|
return initialState;
|
||||||
}
|
}
|
||||||
|
|
||||||
args = { ...state.args };
|
args = { ...args };
|
||||||
|
positions = { ...positions };
|
||||||
|
|
||||||
newWindows = newWindows.filter((win) => {
|
newWindows = newWindows.filter((win) => {
|
||||||
if (win.open && (win.fullscreen || showWindows)) {
|
if (win.open && (win.fullscreen || showWindows)) {
|
||||||
|
@ -486,12 +474,9 @@ export default function windows(
|
||||||
`Cleaning up window from previous session: ${win.windowId}`,
|
`Cleaning up window from previous session: ${win.windowId}`,
|
||||||
);
|
);
|
||||||
delete args[win.windowId];
|
delete args[win.windowId];
|
||||||
|
delete positions[win.windowId];
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
someFullscreen = newWindows.some(
|
|
||||||
(win) => win.fullscreen && !win.hidden,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!showWindows) {
|
if (!showWindows) {
|
||||||
|
@ -499,45 +484,47 @@ export default function windows(
|
||||||
...state,
|
...state,
|
||||||
windows: newWindows,
|
windows: newWindows,
|
||||||
showWindows,
|
showWindows,
|
||||||
someFullscreen,
|
|
||||||
args,
|
args,
|
||||||
|
positions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const xMax = width - SCREEN_MARGIN_EW;
|
const xMax = width - SCREEN_MARGIN_EW;
|
||||||
const yMax = height - SCREEN_MARGIN_S;
|
const yMax = height - SCREEN_MARGIN_S;
|
||||||
let modified = false;
|
let modified = false;
|
||||||
const fixWindows = [];
|
const newPositions = {};
|
||||||
|
|
||||||
for (let i = 0; i < newWindows.length; i += 1) {
|
for (let i = 0; i < newWindows.length; i += 1) {
|
||||||
const win = newWindows[i];
|
const id = newWindows[i].windowId;
|
||||||
const {
|
const {
|
||||||
xPos,
|
xPos,
|
||||||
yPos,
|
yPos,
|
||||||
width: winWidth,
|
width: winWidth,
|
||||||
height: winHeight,
|
height: winHeight,
|
||||||
} = win;
|
} = positions[id];
|
||||||
if (xPos > xMax || yPos > yMax
|
if (xPos > xMax || yPos > yMax
|
||||||
|| width > winWidth || height > winHeight) {
|
|| width > winWidth || height > winHeight) {
|
||||||
modified = true;
|
modified = true;
|
||||||
fixWindows.push({
|
newPositions[id] = {
|
||||||
...win,
|
|
||||||
xPos: Math.min(xMax, xPos),
|
xPos: Math.min(xMax, xPos),
|
||||||
yPos: Math.min(yMax, yPos),
|
yPos: Math.min(yMax, yPos),
|
||||||
width: Math.min(winWidth, width - SCREEN_MARGIN_S),
|
width: Math.min(winWidth, width - SCREEN_MARGIN_S),
|
||||||
height: Math.min(winHeight, height - SCREEN_MARGIN_S),
|
height: Math.min(winHeight, height - SCREEN_MARGIN_S),
|
||||||
});
|
};
|
||||||
} else {
|
} else {
|
||||||
fixWindows.push(win);
|
newPositions[id] = positions[id];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (modified) {
|
||||||
|
positions = newPositions;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
windows: (modified) ? fixWindows : newWindows,
|
windows: newWindows,
|
||||||
showWindows: true,
|
showWindows: true,
|
||||||
someFullscreen,
|
|
||||||
args,
|
args,
|
||||||
|
positions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
46
src/store/selectors/windows.js
Normal file
46
src/store/selectors/windows.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* selectors for window manager
|
||||||
|
*
|
||||||
|
* Memoize heavy selectors or else they recalculate on any store update
|
||||||
|
* see https://redux.js.org/usage/deriving-data-selectors
|
||||||
|
*/
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
|
const selectWindows = (state) => state.windows.windows;
|
||||||
|
export const selectShowWindows = (state) => state.windows.showWindows;
|
||||||
|
|
||||||
|
export const selectIfFullscreen = createSelector(
|
||||||
|
selectWindows,
|
||||||
|
selectShowWindows,
|
||||||
|
(windows, showWindows) => [
|
||||||
|
windows.some((win) => win.fullscreen && !win.hidden) || showWindows,
|
||||||
|
windows.some((win) => win.fullscreen && win.open && !win.hidden),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectActiveWindowIds = createSelector(
|
||||||
|
selectWindows,
|
||||||
|
selectShowWindows,
|
||||||
|
(windows, showWindows) => {
|
||||||
|
if (!showWindows) {
|
||||||
|
windows = windows.filter((win) => win.fullscreen);
|
||||||
|
}
|
||||||
|
return windows.map((win) => win.windowId);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function factory returning a selector for given windowId
|
||||||
|
* use useMemo to cache result
|
||||||
|
*/
|
||||||
|
export const makeSelectWindowById = (windowId) => createSelector(
|
||||||
|
selectWindows,
|
||||||
|
(windows) => windows.find((win) => win.windowId === windowId),
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function factory for non-memorized selector
|
||||||
|
* use useMemo to cache result
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
export const makeSelectWindowPosById = (windowId) => (state) => state.windows.positions[windowId];
|
|
@ -424,7 +424,7 @@ class Renderer {
|
||||||
isLightGrid,
|
isLightGrid,
|
||||||
} = state.gui;
|
} = state.gui;
|
||||||
const {
|
const {
|
||||||
requestingPixel,
|
allowSettingPixel,
|
||||||
} = state.user;
|
} = state.user;
|
||||||
const {
|
const {
|
||||||
view,
|
view,
|
||||||
|
@ -444,13 +444,13 @@ class Renderer {
|
||||||
// if we have to render placeholder
|
// if we have to render placeholder
|
||||||
const doRenderPlaceholder = (
|
const doRenderPlaceholder = (
|
||||||
viewscale >= 3
|
viewscale >= 3
|
||||||
&& requestingPixel
|
&& allowSettingPixel
|
||||||
&& (hover || this.hover)
|
&& (hover || this.hover)
|
||||||
&& !isPotato
|
&& !isPotato
|
||||||
);
|
);
|
||||||
const doRenderPotatoPlaceholder = (
|
const doRenderPotatoPlaceholder = (
|
||||||
viewscale >= 3
|
viewscale >= 3
|
||||||
&& requestingPixel
|
&& allowSettingPixel
|
||||||
&& (hover !== this.hover
|
&& (hover !== this.hover
|
||||||
|| this.forceNextRender
|
|| this.forceNextRender
|
||||||
|| this.forceNextSubrender
|
|| this.forceNextSubrender
|
||||||
|
|
|
@ -398,7 +398,7 @@ class Renderer {
|
||||||
store,
|
store,
|
||||||
} = this;
|
} = this;
|
||||||
const {
|
const {
|
||||||
requestingPixel,
|
allowSettingPixel,
|
||||||
} = store.getState().user;
|
} = store.getState().user;
|
||||||
|
|
||||||
mouse.set(
|
mouse.set(
|
||||||
|
@ -414,7 +414,7 @@ class Renderer {
|
||||||
.add(intersect.face.normal.multiplyScalar(0.5))
|
.add(intersect.face.normal.multiplyScalar(0.5))
|
||||||
.floor()
|
.floor()
|
||||||
.addScalar(0.5);
|
.addScalar(0.5);
|
||||||
if (!requestingPixel
|
if (!allowSettingPixel
|
||||||
|| target.clone().sub(camera.position).length() > 120) {
|
|| target.clone().sub(camera.position).length() > 120) {
|
||||||
rollOverMesh.position.y = -10;
|
rollOverMesh.position.y = -10;
|
||||||
} else {
|
} else {
|
||||||
|
@ -442,7 +442,7 @@ class Renderer {
|
||||||
store,
|
store,
|
||||||
} = this;
|
} = this;
|
||||||
const {
|
const {
|
||||||
requestingPixel,
|
allowSettingPixel,
|
||||||
} = store.getState().user;
|
} = store.getState().user;
|
||||||
|
|
||||||
mouse.set(0, 0);
|
mouse.set(0, 0);
|
||||||
|
@ -454,9 +454,9 @@ class Renderer {
|
||||||
.add(intersect.face.normal.multiplyScalar(0.5))
|
.add(intersect.face.normal.multiplyScalar(0.5))
|
||||||
.floor()
|
.floor()
|
||||||
.addScalar(0.5);
|
.addScalar(0.5);
|
||||||
// TODO make rollOverMesh in a different color while requestingPixel false
|
// TODO make rollOverMesh in a different color while allowSettingPixel false
|
||||||
// instead of hiding it.... we can now queue Voxels
|
// instead of hiding it.... we can now queue Voxels
|
||||||
if (!requestingPixel
|
if (!allowSettingPixel
|
||||||
|| target.clone().sub(camera.position).length() > 50) {
|
|| target.clone().sub(camera.position).length() > 50) {
|
||||||
rollOverMesh.position.y = -10;
|
rollOverMesh.position.y = -10;
|
||||||
} else {
|
} else {
|
||||||
|
@ -482,6 +482,7 @@ class Renderer {
|
||||||
const [i, j] = getChunkOfPixel(canvasSize, x, y, z);
|
const [i, j] = getChunkOfPixel(canvasSize, x, y, z);
|
||||||
const offset = getOffsetOfPixel(canvasSize, x, y, z);
|
const offset = getOffsetOfPixel(canvasSize, x, y, z);
|
||||||
tryPlacePixel(
|
tryPlacePixel(
|
||||||
|
this,
|
||||||
store,
|
store,
|
||||||
i, j,
|
i, j,
|
||||||
offset,
|
offset,
|
||||||
|
@ -578,10 +579,10 @@ class Renderer {
|
||||||
|
|
||||||
const state = this.store.getState();
|
const state = this.store.getState();
|
||||||
const {
|
const {
|
||||||
requestingPixel,
|
allowSettingPixel,
|
||||||
isOnMobile,
|
isOnMobile,
|
||||||
} = state.user;
|
} = state.user;
|
||||||
if (!requestingPixel || isOnMobile) {
|
if (!allowSettingPixel || isOnMobile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,18 +3,19 @@
|
||||||
* Always just one pixelrequest, queue additional requests to send later
|
* Always just one pixelrequest, queue additional requests to send later
|
||||||
* Pixels get predicted on the client and reset if server refused
|
* Pixels get predicted on the client and reset if server refused
|
||||||
*
|
*
|
||||||
|
* TODO move stuff out of here and to actions / middleware
|
||||||
|
* clientPredictions could be in rendererHook
|
||||||
|
*
|
||||||
* */
|
* */
|
||||||
import { t } from 'ttag';
|
import { t } from 'ttag';
|
||||||
import {
|
import {
|
||||||
notify,
|
setAllowSettingPixel,
|
||||||
setRequestingPixel,
|
|
||||||
pAlert,
|
pAlert,
|
||||||
gotCoolDownDelta,
|
storeReceivePixelReturn,
|
||||||
setWait,
|
|
||||||
placedPixels,
|
|
||||||
pixelWait,
|
|
||||||
updatePixel,
|
|
||||||
} from '../store/actions';
|
} from '../store/actions';
|
||||||
|
import {
|
||||||
|
notify,
|
||||||
|
} from '../store/actions/thunks';
|
||||||
import SocketClient from '../socket/SocketClient';
|
import SocketClient from '../socket/SocketClient';
|
||||||
|
|
||||||
let pixelTimeout = null;
|
let pixelTimeout = null;
|
||||||
|
@ -35,8 +36,10 @@ let clientPredictions = [];
|
||||||
*/
|
*/
|
||||||
let lastRequestValues = {};
|
let lastRequestValues = {};
|
||||||
|
|
||||||
|
/*
|
||||||
export function requestFromQueue(store) {
|
* request pixel placement from queue
|
||||||
|
*/
|
||||||
|
function requestFromQueue(store) {
|
||||||
if (!pixelQueue.length) {
|
if (!pixelQueue.length) {
|
||||||
pixelTimeout = null;
|
pixelTimeout = null;
|
||||||
return;
|
return;
|
||||||
|
@ -46,7 +49,7 @@ export function requestFromQueue(store) {
|
||||||
pixelTimeout = setTimeout(() => {
|
pixelTimeout = setTimeout(() => {
|
||||||
pixelQueue = [];
|
pixelQueue = [];
|
||||||
pixelTimeout = null;
|
pixelTimeout = null;
|
||||||
store.dispatch(setRequestingPixel(true));
|
store.dispatch(setAllowSettingPixel(true));
|
||||||
store.dispatch(pAlert(
|
store.dispatch(pAlert(
|
||||||
t`Error :(`,
|
t`Error :(`,
|
||||||
t`Didn't get an answer from pixelplanet. Maybe try to refresh?`,
|
t`Didn't get an answer from pixelplanet. Maybe try to refresh?`,
|
||||||
|
@ -57,11 +60,14 @@ export function requestFromQueue(store) {
|
||||||
lastRequestValues = pixelQueue.shift();
|
lastRequestValues = pixelQueue.shift();
|
||||||
const { i, j, pixels } = lastRequestValues;
|
const { i, j, pixels } = lastRequestValues;
|
||||||
SocketClient.requestPlacePixels(i, j, pixels);
|
SocketClient.requestPlacePixels(i, j, pixels);
|
||||||
store.dispatch(setRequestingPixel(false));
|
store.dispatch(setAllowSettingPixel(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* got pixel update from websocket
|
||||||
|
*/
|
||||||
export function receivePixelUpdate(
|
export function receivePixelUpdate(
|
||||||
store,
|
renderer,
|
||||||
i,
|
i,
|
||||||
j,
|
j,
|
||||||
offset,
|
offset,
|
||||||
|
@ -79,7 +85,7 @@ export function receivePixelUpdate(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
store.dispatch(updatePixel(i, j, offset, color));
|
renderer.renderPixel(i, j, offset, color, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -87,7 +93,7 @@ export function receivePixelUpdate(
|
||||||
* @param i, j, offset data of the first pixel that got rejected
|
* @param i, j, offset data of the first pixel that got rejected
|
||||||
*/
|
*/
|
||||||
function revertPredictionsAt(
|
function revertPredictionsAt(
|
||||||
store,
|
renderer,
|
||||||
sI,
|
sI,
|
||||||
sJ,
|
sJ,
|
||||||
sOffset,
|
sOffset,
|
||||||
|
@ -111,14 +117,18 @@ function revertPredictionsAt(
|
||||||
|
|
||||||
while (p < clientPredictions.length) {
|
while (p < clientPredictions.length) {
|
||||||
const [i, j, offset, color] = clientPredictions[p];
|
const [i, j, offset, color] = clientPredictions[p];
|
||||||
store.dispatch(updatePixel(i, j, offset, color, false));
|
renderer.renderPixel(i, j, offset, color, false);
|
||||||
p += 1;
|
p += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
clientPredictions = [];
|
clientPredictions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* try to place a pixel
|
||||||
|
*/
|
||||||
export function tryPlacePixel(
|
export function tryPlacePixel(
|
||||||
|
renderer,
|
||||||
store,
|
store,
|
||||||
i,
|
i,
|
||||||
j,
|
j,
|
||||||
|
@ -126,7 +136,7 @@ export function tryPlacePixel(
|
||||||
color,
|
color,
|
||||||
curColor,
|
curColor,
|
||||||
) {
|
) {
|
||||||
store.dispatch(updatePixel(i, j, offset, color, false));
|
renderer.renderPixel(i, j, offset, color, false);
|
||||||
clientPredictions.push([i, j, offset, curColor, color]);
|
clientPredictions.push([i, j, offset, curColor, color]);
|
||||||
|
|
||||||
if (pixelQueue.length) {
|
if (pixelQueue.length) {
|
||||||
|
@ -150,28 +160,26 @@ export function tryPlacePixel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* got return from pixel request
|
||||||
|
*/
|
||||||
export function receivePixelReturn(
|
export function receivePixelReturn(
|
||||||
store,
|
store,
|
||||||
retCode,
|
renderer,
|
||||||
wait,
|
args,
|
||||||
coolDownSeconds,
|
|
||||||
pxlCnt,
|
|
||||||
rankedPxlCnt,
|
|
||||||
) {
|
) {
|
||||||
clearTimeout(pixelTimeout);
|
clearTimeout(pixelTimeout);
|
||||||
|
|
||||||
/*
|
store.dispatch(storeReceivePixelReturn(args));
|
||||||
* the terms coolDown is used in a different meaning here
|
|
||||||
* coolDown is the delta seconds of the placed pixel
|
const {
|
||||||
*/
|
retCode,
|
||||||
if (wait) {
|
coolDownSeconds,
|
||||||
store.dispatch(setWait(wait));
|
pxlCnt,
|
||||||
}
|
} = args;
|
||||||
|
|
||||||
if (coolDownSeconds) {
|
if (coolDownSeconds) {
|
||||||
store.dispatch(notify(coolDownSeconds));
|
store.dispatch(notify(coolDownSeconds));
|
||||||
if (coolDownSeconds < 0) {
|
|
||||||
store.dispatch(gotCoolDownDelta(coolDownSeconds));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retCode) {
|
if (retCode) {
|
||||||
|
@ -181,7 +189,7 @@ export function receivePixelReturn(
|
||||||
*/
|
*/
|
||||||
const { i, j, pixels } = lastRequestValues;
|
const { i, j, pixels } = lastRequestValues;
|
||||||
const [offset] = pixels[pxlCnt];
|
const [offset] = pixels[pxlCnt];
|
||||||
revertPredictionsAt(store, i, j, offset);
|
revertPredictionsAt(renderer, i, j, offset);
|
||||||
pixelQueue = [];
|
pixelQueue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +198,6 @@ export function receivePixelReturn(
|
||||||
let type = 'error';
|
let type = 'error';
|
||||||
switch (retCode) {
|
switch (retCode) {
|
||||||
case 0:
|
case 0:
|
||||||
store.dispatch(placedPixels(rankedPxlCnt));
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
errorTitle = t`Invalid Canvas`;
|
errorTitle = t`Invalid Canvas`;
|
||||||
|
@ -226,7 +233,6 @@ export function receivePixelReturn(
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
// pixestack used up
|
// pixestack used up
|
||||||
store.dispatch(pixelWait());
|
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
errorTitle = 'Captcha';
|
errorTitle = 'Captcha';
|
||||||
|
@ -267,11 +273,6 @@ export function receivePixelReturn(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch(setRequestingPixel(true));
|
requestFromQueue(store);
|
||||||
|
|
||||||
if (!msg) {
|
|
||||||
/* start next request if queue isn't empty */
|
|
||||||
requestFromQueue(store);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user