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",
|
||||
"image-q": "^4.0.0",
|
||||
"js-file-download": "^0.4.12",
|
||||
"localforage": "^1.10.0",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^1.4.4",
|
||||
"mysql2": "^2.3.3",
|
||||
|
@ -42,6 +41,7 @@
|
|||
"redux-logger": "^3.0.6",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-thunk": "^2.4.1",
|
||||
"reselect": "^4.1.6",
|
||||
"sequelize": "^6.21.3",
|
||||
"sharp": "^0.30.7",
|
||||
"startaudiocontext": "^1.2.1",
|
||||
|
@ -6301,11 +6301,6 @@
|
|||
"@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": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
|
@ -7097,14 +7092,6 @@
|
|||
"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": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
|
@ -7134,14 +7121,6 @@
|
|||
"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": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
|
@ -9177,6 +9156,11 @@
|
|||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||
"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": {
|
||||
"version": "1.22.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||
|
@ -15913,11 +15897,6 @@
|
|||
"@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": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
|
@ -16506,14 +16485,6 @@
|
|||
"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": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
|
@ -16537,14 +16508,6 @@
|
|||
"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": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
|
@ -18047,6 +18010,11 @@
|
|||
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
|
||||
"dev": true
|
||||
},
|
||||
"reselect": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.6.tgz",
|
||||
"integrity": "sha512-ZovIuXqto7elwnxyXbBtCPo9YFEr3uJqj2rRbcOOog1bmu2Ag85M4hixSwFWyaBMKXNgvPaJ9OSu9SkBPIeJHQ=="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.22.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
"express-session": "^1.17.2",
|
||||
"image-q": "^4.0.0",
|
||||
"js-file-download": "^0.4.12",
|
||||
"localforage": "^1.10.0",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^1.4.4",
|
||||
"mysql2": "^2.3.3",
|
||||
|
@ -56,6 +55,7 @@
|
|||
"redux-logger": "^3.0.6",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-thunk": "^2.4.1",
|
||||
"reselect": "^4.1.6",
|
||||
"sequelize": "^6.21.3",
|
||||
"sharp": "^0.30.7",
|
||||
"startaudiocontext": "^1.2.1",
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
import createKeyPressHandler from './controls/keypress';
|
||||
import {
|
||||
fetchMe,
|
||||
initTimer,
|
||||
urlChange,
|
||||
receiveOnline,
|
||||
|
@ -15,6 +14,9 @@ import {
|
|||
setMobile,
|
||||
windowResize,
|
||||
} from './store/actions';
|
||||
import {
|
||||
fetchMe,
|
||||
} from './store/actions/thunks';
|
||||
import {
|
||||
receivePixelUpdate,
|
||||
receivePixelReturn,
|
||||
|
@ -36,12 +38,12 @@ function init() {
|
|||
pixels.forEach((pxl) => {
|
||||
const [offset, color] = pxl;
|
||||
// remove protection
|
||||
receivePixelUpdate(store, i, j, offset, color & 0x7F);
|
||||
receivePixelUpdate(getRenderer(), i, j, offset, color & 0x7F);
|
||||
});
|
||||
});
|
||||
SocketClient.on('pixelReturn',
|
||||
(args) => receivePixelReturn(store, ...args),
|
||||
);
|
||||
SocketClient.on('pixelReturn', (args) => {
|
||||
receivePixelReturn(store, getRenderer(), args);
|
||||
});
|
||||
SocketClient.on('cooldownPacket', (coolDown) => {
|
||||
store.dispatch(receiveCoolDown(coolDown));
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
|||
import { t } from 'ttag';
|
||||
|
||||
import useInterval from './hooks/interval';
|
||||
import { showHelpModal } from '../store/actions';
|
||||
import { showHelpModal } from '../store/actions/windows';
|
||||
import {
|
||||
largeDurationToString,
|
||||
} from '../core/utils';
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useSelector, useDispatch } from 'react-redux';
|
|||
import { t } from 'ttag';
|
||||
|
||||
import copy from '../utils/clipboard';
|
||||
import { notify } from '../store/actions';
|
||||
import { notify } from '../store/actions/thunks';
|
||||
|
||||
|
||||
function renderCoordinates(cell) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import React, { useState } from 'react';
|
|||
import { useDispatch } from 'react-redux';
|
||||
import { t } from 'ttag';
|
||||
|
||||
import { notify } from '../store/actions';
|
||||
import { notify } from '../store/actions/thunks';
|
||||
import copyTextToClipboard from '../utils/clipboard';
|
||||
import {
|
||||
requestIID,
|
||||
|
|
|
@ -5,7 +5,7 @@ import { useDispatch } from 'react-redux';
|
|||
import { t } from 'ttag';
|
||||
|
||||
import LogInForm from './LogInForm';
|
||||
import { changeWindowType } from '../store/actions';
|
||||
import { changeWindowType } from '../store/actions/windows';
|
||||
|
||||
const logoStyle = {
|
||||
marginRight: 5,
|
||||
|
|
|
@ -9,7 +9,7 @@ import { t } from 'ttag';
|
|||
import {
|
||||
setBlockingDm,
|
||||
setUserBlock,
|
||||
} from '../store/actions';
|
||||
} from '../store/actions/thunks';
|
||||
import MdToggleButton from './MdToggleButton';
|
||||
|
||||
const SocialSettings = ({ done }) => {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
|
||||
import React, {
|
||||
useState, useCallback, useRef, useEffect,
|
||||
useState, useCallback, useRef, useEffect, useMemo,
|
||||
} from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { t } from 'ttag';
|
||||
|
@ -16,21 +16,26 @@ import {
|
|||
toggleMaximizeWindow,
|
||||
cloneWindow,
|
||||
focusWindow,
|
||||
} from '../store/actions';
|
||||
} from '../store/actions/windows';
|
||||
import {
|
||||
makeSelectWindowById,
|
||||
makeSelectWindowPosById,
|
||||
selectShowWindows,
|
||||
} from '../store/selectors/windows';
|
||||
import useDrag from './hooks/drag';
|
||||
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 [render, setRender] = useState(false);
|
||||
|
||||
const titleBarRef = useRef(null);
|
||||
const resizeRef = useRef(null);
|
||||
|
||||
const win = useSelector((state) => selectWindowById(state, id));
|
||||
const showWindows = useSelector((state) => state.windows.showWindows);
|
||||
const selectWindowById = useMemo(() => makeSelectWindowById(id), []);
|
||||
const selectWIndowPosById = useMemo(() => makeSelectWindowPosById(id), []);
|
||||
const win = useSelector(selectWindowById);
|
||||
const position = useSelector(selectWIndowPosById);
|
||||
const showWindows = useSelector(selectShowWindows);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
@ -101,12 +106,14 @@ const Window = ({ id }) => {
|
|||
}
|
||||
|
||||
const {
|
||||
width, height,
|
||||
xPos, yPos,
|
||||
windowType,
|
||||
z,
|
||||
title,
|
||||
} = win;
|
||||
const {
|
||||
xPos, yPos,
|
||||
width, height,
|
||||
z,
|
||||
} = position;
|
||||
|
||||
const [Content, name] = COMPONENTS[windowType];
|
||||
|
||||
|
@ -155,10 +162,6 @@ const Window = ({ id }) => {
|
|||
);
|
||||
}
|
||||
|
||||
if (!showWindows) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`window ${extraClasses}`}
|
||||
|
|
|
@ -9,29 +9,21 @@ import Window from './Window';
|
|||
import Overlay from './Overlay';
|
||||
import {
|
||||
closeFullscreenWindows,
|
||||
} from '../store/actions';
|
||||
|
||||
// eslint-disable-next-line max-len
|
||||
const selectWindowIds = (state) => state.windows.windows.map((win) => win.windowId);
|
||||
// eslint-disable-next-line max-len
|
||||
const selectMeta = (state) => {
|
||||
console.log('check');
|
||||
return [
|
||||
state.windows.showWindows,
|
||||
state.windows.someFullscreen,
|
||||
state.windows.windows.some((win) => win.fullscreen && win.open && !win.hidden),
|
||||
]};
|
||||
} from '../store/actions/windows';
|
||||
import {
|
||||
selectIfFullscreen,
|
||||
selectActiveWindowIds,
|
||||
} from '../store/selectors/windows';
|
||||
|
||||
const WindowManager = () => {
|
||||
const windowIds = useSelector(selectWindowIds, shallowEqual);
|
||||
const windowIds = useSelector(selectActiveWindowIds, shallowEqual);
|
||||
const [
|
||||
showWindows,
|
||||
someFullscreen,
|
||||
fullscreenExistOrShowWindows,
|
||||
someOpenFullscreen,
|
||||
] = useSelector(selectMeta, shallowEqual);
|
||||
] = useSelector(selectIfFullscreen, shallowEqual);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
if ((!showWindows && !someFullscreen) || !windowIds.length) {
|
||||
if (!fullscreenExistOrShowWindows || !windowIds.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
|||
import { FaFlipboard } from 'react-icons/fa';
|
||||
import { t } from 'ttag';
|
||||
|
||||
import { showCanvasSelectionModal } from '../../store/actions';
|
||||
import { showCanvasSelectionModal } from '../../store/actions/windows';
|
||||
|
||||
|
||||
const CanvasSwitchButton = () => {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { t } from 'ttag';
|
|||
import {
|
||||
hideAllWindowTypes,
|
||||
openChatWindow,
|
||||
} from '../../store/actions';
|
||||
} from '../../store/actions/windows';
|
||||
|
||||
/*
|
||||
* return [ chatOpen, chatHiden ]
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
|||
import { FaQuestion } from 'react-icons/fa';
|
||||
import { t } from 'ttag';
|
||||
|
||||
import { showHelpModal } from '../../store/actions';
|
||||
import { showHelpModal } from '../../store/actions/windows';
|
||||
|
||||
|
||||
const HelpButton = () => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
|||
import { MdPerson } from 'react-icons/md';
|
||||
import { t } from 'ttag';
|
||||
|
||||
import { showUserAreaModal } from '../../store/actions';
|
||||
import { showUserAreaModal } from '../../store/actions/windows';
|
||||
|
||||
|
||||
const LogInButton = () => {
|
||||
|
|
|
@ -7,7 +7,7 @@ import { useDispatch } from 'react-redux';
|
|||
import { FaCog } from 'react-icons/fa';
|
||||
import { t } from 'ttag';
|
||||
|
||||
import { showSettingsModal } from '../../store/actions';
|
||||
import { showSettingsModal } from '../../store/actions/windows';
|
||||
|
||||
|
||||
const SettingsButton = () => {
|
||||
|
|
|
@ -11,10 +11,12 @@ import {
|
|||
} from '../hooks/clickOutside';
|
||||
import {
|
||||
hideContextMenu,
|
||||
setLeaveChannel,
|
||||
muteChatChannel,
|
||||
unmuteChatChannel,
|
||||
} from '../../store/actions';
|
||||
import {
|
||||
setLeaveChannel,
|
||||
} from '../../store/actions/thunks';
|
||||
|
||||
const ChannelContextMenu = () => {
|
||||
const wrapperRef = useRef(null);
|
||||
|
|
|
@ -11,11 +11,15 @@ import {
|
|||
} from '../hooks/clickOutside';
|
||||
import {
|
||||
hideContextMenu,
|
||||
addToChatInputMessage,
|
||||
} from '../../store/actions';
|
||||
import {
|
||||
startDm,
|
||||
setUserBlock,
|
||||
} from '../../store/actions/thunks';
|
||||
import {
|
||||
addToChatInputMessage,
|
||||
setWindowArgs,
|
||||
} from '../../store/actions';
|
||||
} from '../../store/actions/windows';
|
||||
import { escapeMd } from '../../core/utils';
|
||||
|
||||
const UserContextMenu = () => {
|
||||
|
|
|
@ -7,7 +7,8 @@ import { useDispatch, useSelector, shallowEqual } from 'react-redux';
|
|||
import { t } from 'ttag';
|
||||
|
||||
import CanvasItem from '../CanvasItem';
|
||||
import { changeWindowType, selectCanvas } from '../../store/actions';
|
||||
import { selectCanvas } from '../../store/actions';
|
||||
import { changeWindowType } from '../../store/actions/windows';
|
||||
|
||||
|
||||
const CanvasSelect = ({ windowId }) => {
|
||||
|
|
|
@ -13,13 +13,17 @@ import ChatMessage from '../ChatMessage';
|
|||
import ChannelDropDown from '../contextmenus/ChannelDropDown';
|
||||
|
||||
import {
|
||||
showUserAreaModal,
|
||||
fetchChatMessages,
|
||||
showContextMenu,
|
||||
setWindowTitle,
|
||||
setWindowArgs,
|
||||
markChannelAsRead,
|
||||
} from '../../store/actions';
|
||||
import {
|
||||
showUserAreaModal,
|
||||
setWindowTitle,
|
||||
setWindowArgs,
|
||||
} from '../../store/actions/windows';
|
||||
import {
|
||||
fetchChatMessages,
|
||||
} from '../../store/actions/thunks';
|
||||
import SocketClient from '../../socket/SocketClient';
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import React, { useState } from 'react';
|
|||
import { useDispatch } from 'react-redux';
|
||||
import { t } from 'ttag';
|
||||
|
||||
import { changeWindowType } from '../../store/actions';
|
||||
import { changeWindowType } from '../../store/actions/windows';
|
||||
import { validateEMail } from '../../utils/validation';
|
||||
import { requestNewPassword } from '../../store/actions/fetch';
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ import {
|
|||
} from '../../utils/validation';
|
||||
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) {
|
||||
|
|
|
@ -8,8 +8,10 @@ import { t } from 'ttag';
|
|||
|
||||
import {
|
||||
fetchStats,
|
||||
} from '../../store/actions/thunks';
|
||||
import {
|
||||
setWindowArgs,
|
||||
} from '../../store/actions';
|
||||
} from '../../store/actions/windows';
|
||||
import useInterval from '../hooks/interval';
|
||||
import LogInArea from '../LogInArea';
|
||||
import Tabs from '../Tabs';
|
||||
|
|
|
@ -243,6 +243,7 @@ class PixelPlainterControls {
|
|||
const [i, j] = getChunkOfPixel(canvasSize, x, y);
|
||||
const offset = getOffsetOfPixel(canvasSize, x, y);
|
||||
tryPlacePixel(
|
||||
renderer,
|
||||
store,
|
||||
i, j, offset,
|
||||
selectedColor,
|
||||
|
|
|
@ -9,9 +9,11 @@ import {
|
|||
toggleHiddenCanvases,
|
||||
togglePixelNotify,
|
||||
toggleMute,
|
||||
notify,
|
||||
selectCanvas,
|
||||
} from '../store/actions';
|
||||
import {
|
||||
notify,
|
||||
} from '../store/actions/thunks';
|
||||
|
||||
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.`,
|
||||
e.reason,
|
||||
);
|
||||
|
||||
setTimeout(() => this.connect(), 5000);
|
||||
setTimeout(() => this.connect(), timeout);
|
||||
}
|
||||
|
||||
reconnect() {
|
||||
|
|
|
@ -9,13 +9,13 @@ export default {
|
|||
const coolDownSeconds = data.getInt16(6);
|
||||
const pxlCnt = data.getUint8(8);
|
||||
const rankedPxlCnt = data.getUint8(9);
|
||||
return [
|
||||
return {
|
||||
retCode,
|
||||
wait,
|
||||
coolDownSeconds,
|
||||
pxlCnt,
|
||||
rankedPxlCnt,
|
||||
];
|
||||
};
|
||||
},
|
||||
dehydrate(
|
||||
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 {
|
||||
requestStartDm,
|
||||
requestBlock,
|
||||
requestBlockDm,
|
||||
requestLeaveChan,
|
||||
requestRankings,
|
||||
requestMe,
|
||||
} from './fetch';
|
||||
|
||||
export function pAlert(
|
||||
title,
|
||||
message,
|
||||
|
@ -115,27 +106,10 @@ export function toggleOpenMenu() {
|
|||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* requestingPixel is inveted, it has the meaning of
|
||||
* "can i request a pixel"
|
||||
*/
|
||||
export function setRequestingPixel(requestingPixel) {
|
||||
export function setAllowSettingPixel(allowSettingPixel) {
|
||||
return {
|
||||
type: 'SET_REQUESTING_PIXEL',
|
||||
requestingPixel,
|
||||
};
|
||||
}
|
||||
|
||||
export function setNotification(notification) {
|
||||
return {
|
||||
type: 'SET_NOTIFICATION',
|
||||
notification,
|
||||
};
|
||||
}
|
||||
|
||||
export function unsetNotification() {
|
||||
return {
|
||||
type: 'UNSET_NOTIFICATION',
|
||||
type: 'ALLOW_SETTING_PIXEL',
|
||||
allowSettingPixel,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -152,13 +126,6 @@ export function unsetHover() {
|
|||
};
|
||||
}
|
||||
|
||||
export function setWait(wait) {
|
||||
return {
|
||||
type: 'SET_WAIT',
|
||||
wait,
|
||||
};
|
||||
}
|
||||
|
||||
export function setMobile(mobile) {
|
||||
return {
|
||||
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) {
|
||||
return {
|
||||
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(
|
||||
me,
|
||||
) {
|
||||
|
@ -399,13 +279,6 @@ export function receiveMe(
|
|||
};
|
||||
}
|
||||
|
||||
export function logoutUser(
|
||||
) {
|
||||
return {
|
||||
type: 'LOGOUT',
|
||||
};
|
||||
}
|
||||
|
||||
export function receiveStats(
|
||||
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(
|
||||
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(
|
||||
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) {
|
||||
return {
|
||||
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(
|
||||
menuType,
|
||||
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() {
|
||||
return {
|
||||
type: 'HIDE_CONTEXT_MENU',
|
||||
|
@ -1004,3 +531,4 @@ export function urlChange() {
|
|||
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 { persistStore, persistCombineReducers } from 'redux-persist';
|
||||
import localForage from 'localforage';
|
||||
import { persistStore, persistReducer } from 'redux-persist';
|
||||
import storage from 'redux-persist/lib/storage';
|
||||
|
||||
/*
|
||||
* reducers
|
||||
|
@ -29,12 +37,23 @@ import array from './middleware/array';
|
|||
import promise from './middleware/promise';
|
||||
import notifications from './middleware/notifications';
|
||||
import title from './middleware/title';
|
||||
import placePixelControl from './middleware/placePixelControl';
|
||||
// import placePixelControl from './middleware/placePixelControl';
|
||||
import extensions from './middleware/extensions';
|
||||
|
||||
const reducers = persistCombineReducers({
|
||||
const CURRENT_VERSION = 3;
|
||||
|
||||
const reducers = persistReducer({
|
||||
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: [
|
||||
'user',
|
||||
'canvas',
|
||||
|
@ -43,7 +62,7 @@ const reducers = persistCombineReducers({
|
|||
'contextMenu',
|
||||
'fetching',
|
||||
],
|
||||
}, {
|
||||
}, combineReducers({
|
||||
audio,
|
||||
canvas,
|
||||
gui,
|
||||
|
@ -55,7 +74,7 @@ const reducers = persistCombineReducers({
|
|||
contextMenu,
|
||||
chatRead,
|
||||
fetching,
|
||||
});
|
||||
}));
|
||||
|
||||
const store = createStore(
|
||||
reducers,
|
||||
|
@ -70,7 +89,7 @@ const store = createStore(
|
|||
title,
|
||||
socketClientHook,
|
||||
rendererHook,
|
||||
placePixelControl,
|
||||
// placePixelControl,
|
||||
extensions,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -68,30 +68,6 @@ export default (store) => (next) => (action) => {
|
|||
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': {
|
||||
const oscillatorNode = context.createOscillator();
|
||||
const gainNode = context.createGain();
|
||||
|
@ -143,40 +119,62 @@ export default (store) => (next) => (action) => {
|
|||
break;
|
||||
}
|
||||
|
||||
case 'PLACED_PIXELS': {
|
||||
const { palette, selectedColor: color } = state.canvas;
|
||||
const colorsAmount = palette.colors.length;
|
||||
case 'RECEIVE_PIXEL_RETURN': {
|
||||
switch (action.retCode) {
|
||||
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 oscillatorNode = context.createOscillator();
|
||||
const gainNode = context.createGain();
|
||||
const { currentTime } = context;
|
||||
const clrFreq = 100 + Math.log(color / colorsAmount + 1) * 300;
|
||||
const oscillatorNode = context.createOscillator();
|
||||
const gainNode = context.createGain();
|
||||
const { currentTime } = context;
|
||||
|
||||
oscillatorNode.type = 'sine';
|
||||
oscillatorNode.frequency.setValueAtTime(clrFreq, currentTime);
|
||||
oscillatorNode.frequency.exponentialRampToValueAtTime(
|
||||
1400,
|
||||
currentTime + 0.2,
|
||||
);
|
||||
oscillatorNode.type = 'sine';
|
||||
oscillatorNode.start(currentTime);
|
||||
oscillatorNode.frequency.setValueAtTime(clrFreq, currentTime);
|
||||
oscillatorNode.frequency.exponentialRampToValueAtTime(
|
||||
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);
|
||||
gainNode.gain.exponentialRampToValueAtTime(
|
||||
0.2,
|
||||
currentTime + 0.1,
|
||||
);
|
||||
|
||||
oscillatorNode.connect(gainNode);
|
||||
gainNode.connect(context.destination);
|
||||
|
||||
oscillatorNode.start();
|
||||
oscillatorNode.stop(currentTime + 0.1);
|
||||
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;
|
||||
}
|
||||
default:
|
||||
// nothing
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'COOLDOWN_END': {
|
||||
// do not play sound if last cooldown end was <5s ago
|
||||
const { lastCoolDownEnd } = state.user;
|
||||
if (lastCoolDownEnd && lastCoolDownEnd.getTime() + 5000 > Date.now()) {
|
||||
if (lastCoolDownEnd && lastCoolDownEnd + 5000 > Date.now()) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,14 +2,13 @@
|
|||
* Notifications
|
||||
*
|
||||
*/
|
||||
|
||||
import { t } from 'ttag';
|
||||
|
||||
export default (store) => (next) => (action) => {
|
||||
try {
|
||||
if (!document.hasFocus()) {
|
||||
switch (action.type) {
|
||||
case 'RECEIVE_ME':
|
||||
case 'PLACED_PIXELS': {
|
||||
case 'RECEIVE_ME': {
|
||||
if (window.Notification
|
||||
&& Notification.permission !== 'granted'
|
||||
&& Notification.permission !== 'denied'
|
||||
|
@ -25,17 +24,17 @@ export default (store) => (next) => (action) => {
|
|||
// do not notify if last cooldown end was <15s ago
|
||||
const { lastCoolDownEnd } = state.user;
|
||||
if (lastCoolDownEnd
|
||||
&& lastCoolDownEnd.getTime() + 15000 > Date.now()) {
|
||||
&& lastCoolDownEnd + 15000 > Date.now()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (window.Notification && Notification.permission === 'granted') {
|
||||
// eslint-disable-next-line no-new
|
||||
new Notification('Your next pixels are ready', {
|
||||
new Notification(t`Your next pixels are ready`, {
|
||||
icon: '/tile.png',
|
||||
silent: false,
|
||||
vibrate: [200, 100],
|
||||
body: 'You can now place more on pixelplanet.fun :)',
|
||||
body: t`You can now place more on pixelplanet.fun :)`,
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
@ -52,11 +51,11 @@ export default (store) => (next) => (action) => {
|
|||
|
||||
if (window.Notification && Notification.permission === 'granted') {
|
||||
// eslint-disable-next-line no-new
|
||||
new Notification(`${name} mentioned you`, {
|
||||
new Notification(`${name} ${t`mentioned you`}`, {
|
||||
icon: '/tile.png',
|
||||
silent: false,
|
||||
vibrate: [200, 100],
|
||||
body: 'You have new messages in chat',
|
||||
body: t`You have new messages in chat`,
|
||||
});
|
||||
}
|
||||
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) => {
|
||||
const ret = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case 'CLOSE_ALERT': {
|
||||
requestFromQueue(store);
|
||||
case 'RECEIVE_PIXEL_RETURN': {
|
||||
const renderer = getRenderer();
|
||||
const {
|
||||
retCode,
|
||||
wait,
|
||||
coolDownSeconds,
|
||||
pxlCnt,
|
||||
rankedPxlCnt,
|
||||
} = action;
|
||||
receivePixelReturn(
|
||||
store,
|
||||
renderer,
|
||||
retCode,
|
||||
wait,
|
||||
coolDownSeconds,
|
||||
pxlCnt,
|
||||
rankedPxlCnt,
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// nothing
|
||||
}
|
||||
|
||||
return next(action);
|
||||
return ret;
|
||||
};
|
||||
|
|
|
@ -95,7 +95,7 @@ export default (store) => (next) => (action) => {
|
|||
}
|
||||
|
||||
case 'TOGGLE_GRID':
|
||||
case 'SET_REQUESTING_PIXEL': {
|
||||
case 'ALLOW_SETTING_PIXEL': {
|
||||
const renderer = getRenderer();
|
||||
renderer.forceNextSubrender = true;
|
||||
break;
|
||||
|
@ -108,30 +108,21 @@ export default (store) => (next) => (action) => {
|
|||
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': {
|
||||
const renderer = getRenderer();
|
||||
renderer.updateView(state);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'COOLDOWN_DELTA': {
|
||||
const { delta } = action;
|
||||
case 'RECEIVE_PIXEL_RETURN': {
|
||||
const renderer = getRenderer();
|
||||
if (renderer && renderer.controls && renderer.controls.gotCoolDownDelta) {
|
||||
renderer.controls.gotCoolDownDelta(delta * -1);
|
||||
renderer.forceNextSubrender = true;
|
||||
const { coolDownSeconds } = action;
|
||||
if (coolDownSeconds < 0
|
||||
&& renderer && renderer.controls
|
||||
&& renderer.controls.gotCoolDownDelta
|
||||
) {
|
||||
renderer.controls.gotCoolDownDelta(coolDownSeconds * -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -24,11 +24,16 @@ export default function ranks(
|
|||
action,
|
||||
) {
|
||||
switch (action.type) {
|
||||
case 'PLACED_PIXELS': {
|
||||
case 'RECEIVE_PIXEL_RETURN': {
|
||||
const {
|
||||
rankedPxlCnt,
|
||||
} = action;
|
||||
if (!rankedPxlCnt) {
|
||||
return state;
|
||||
}
|
||||
let { totalPixels, dailyTotalPixels } = state;
|
||||
const { amount } = action;
|
||||
totalPixels += amount;
|
||||
dailyTotalPixels += amount;
|
||||
totalPixels += rankedPxlCnt;
|
||||
dailyTotalPixels += rankedPxlCnt;
|
||||
return {
|
||||
...state,
|
||||
totalPixels,
|
||||
|
|
|
@ -4,7 +4,7 @@ const initialState = {
|
|||
wait: null,
|
||||
coolDown: null, // ms
|
||||
lastCoolDownEnd: null,
|
||||
requestingPixel: true,
|
||||
allowSettingPixel: true,
|
||||
// messages are sent by api/me, like not_verified status
|
||||
messages: [],
|
||||
mailreg: false,
|
||||
|
@ -35,34 +35,34 @@ export default function user(
|
|||
return {
|
||||
...state,
|
||||
coolDown: null,
|
||||
lastCoolDownEnd: new Date(),
|
||||
lastCoolDownEnd: Date().now(),
|
||||
wait: null,
|
||||
};
|
||||
}
|
||||
|
||||
case 'SET_REQUESTING_PIXEL': {
|
||||
const { requestingPixel } = action;
|
||||
case 'ALLOW_SETTING_PIXEL': {
|
||||
const { allowSettingPixel } = action;
|
||||
return {
|
||||
...state,
|
||||
requestingPixel,
|
||||
allowSettingPixel,
|
||||
};
|
||||
}
|
||||
|
||||
case 'SET_WAIT': {
|
||||
const { wait: duration } = action;
|
||||
const wait = duration
|
||||
? new Date(Date.now() + duration)
|
||||
: null;
|
||||
case 'RECEIVE_PIXEL_RETURN': {
|
||||
const {
|
||||
wait: duration,
|
||||
} = action;
|
||||
return {
|
||||
...state,
|
||||
wait,
|
||||
wait: (duration) ? Date.now() + duration : state.wait,
|
||||
allowSettingPixel: true,
|
||||
};
|
||||
}
|
||||
|
||||
case 'RECEIVE_COOLDOWN': {
|
||||
const { wait: duration } = action;
|
||||
const wait = duration
|
||||
? new Date(Date.now() + duration)
|
||||
? Date.now() + duration
|
||||
: null;
|
||||
return {
|
||||
...state,
|
||||
|
|
|
@ -73,13 +73,20 @@ function clampPos(prefXPos, prefYPos, width, height) {
|
|||
*/
|
||||
function sortWindows(newState, force = false) {
|
||||
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));
|
||||
newState.windows = newState.windows.map((win) => ({
|
||||
...win,
|
||||
z: orderedZ.indexOf(win.z),
|
||||
}));
|
||||
for (let i = 0; i < ids.length; i += 1) {
|
||||
const id = ids[i];
|
||||
positions[id] = {
|
||||
...positions[id],
|
||||
z: orderedZ.indexOf(positions[id].z),
|
||||
};
|
||||
}
|
||||
newState.zMax = orderedZ.length - 1;
|
||||
newState.positions = positions;
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
@ -87,8 +94,6 @@ function sortWindows(newState, force = false) {
|
|||
const initialState = {
|
||||
// if windows get shown, false on small screens
|
||||
showWindows: window.innerWidth > SCREEN_WIDTH_THRESHOLD,
|
||||
// if at least one window is in fullscreen
|
||||
someFullscreen: false,
|
||||
// highest zIndex of window
|
||||
zMax: 0,
|
||||
// [
|
||||
|
@ -97,20 +102,25 @@ const initialState = {
|
|||
// open: boolean,
|
||||
// hidden: boolean,
|
||||
// fullscreen: boolean,
|
||||
// z: number,
|
||||
// windowType: string,
|
||||
// title: string,
|
||||
// title that is additionally shown to the window-type-title
|
||||
// width: number,
|
||||
// height: number,
|
||||
// xPos: percentage,
|
||||
// yPos: percentage,
|
||||
// cloneable: boolean,
|
||||
// },
|
||||
// ]
|
||||
windows: [],
|
||||
// {
|
||||
// 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 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({
|
||||
...state,
|
||||
someFullscreen,
|
||||
zMax: newZMax,
|
||||
windows: newWindows,
|
||||
windows: [
|
||||
...state.windows,
|
||||
{
|
||||
windowId,
|
||||
windowType,
|
||||
open: true,
|
||||
hidden: false,
|
||||
fullscreen,
|
||||
title,
|
||||
cloneable,
|
||||
},
|
||||
],
|
||||
args: {
|
||||
...state.args,
|
||||
[windowId]: {
|
||||
...args,
|
||||
},
|
||||
},
|
||||
positions: {
|
||||
...state.positions,
|
||||
[windowId]: {
|
||||
width,
|
||||
height,
|
||||
xPos,
|
||||
yPos,
|
||||
z: newZMax,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -193,12 +202,15 @@ export default function windows(
|
|||
windowId,
|
||||
} = action;
|
||||
const args = { ...state.args };
|
||||
const positions = { ...state.positions };
|
||||
delete args[windowId];
|
||||
delete positions[windowId];
|
||||
|
||||
return {
|
||||
...state,
|
||||
windows: state.windows.filter((win) => win.windowId !== windowId),
|
||||
args,
|
||||
positions,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -215,13 +227,8 @@ export default function windows(
|
|||
};
|
||||
});
|
||||
|
||||
const someFullscreen = newWindows.some(
|
||||
(win) => win.fullscreen && !win.hidden,
|
||||
);
|
||||
|
||||
return {
|
||||
...state,
|
||||
someFullscreen,
|
||||
windows: newWindows,
|
||||
};
|
||||
}
|
||||
|
@ -238,13 +245,8 @@ export default function windows(
|
|||
};
|
||||
});
|
||||
|
||||
const someFullscreen = newWindows.some(
|
||||
(win) => win.fullscreen && !win.hidden,
|
||||
);
|
||||
|
||||
return {
|
||||
...state,
|
||||
someFullscreen,
|
||||
windows: newWindows,
|
||||
};
|
||||
}
|
||||
|
@ -272,6 +274,7 @@ export default function windows(
|
|||
windowId,
|
||||
} = action;
|
||||
const win = state.windows.find((w) => w.windowId === windowId);
|
||||
const position = state.positions[windowId];
|
||||
const newWindowId = generateWindowId(state);
|
||||
const newZMax = state.zMax + 1;
|
||||
const {
|
||||
|
@ -286,9 +289,6 @@ export default function windows(
|
|||
{
|
||||
...win,
|
||||
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: {
|
||||
|
@ -297,6 +297,15 @@ export default function windows(
|
|||
...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 {
|
||||
...state,
|
||||
someFullscreen,
|
||||
args,
|
||||
windows: newWindows,
|
||||
};
|
||||
|
@ -338,29 +342,22 @@ export default function windows(
|
|||
windowId,
|
||||
} = action;
|
||||
const {
|
||||
windows: oldWindows, zMax,
|
||||
zMax,
|
||||
} = state;
|
||||
|
||||
const newWindows = [];
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
const { z } = state.positions[windowId];
|
||||
if (z === zMax) {
|
||||
return state;
|
||||
}
|
||||
return sortWindows({
|
||||
...state,
|
||||
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 {
|
||||
...state,
|
||||
someFullscreen,
|
||||
windows: newWindows,
|
||||
};
|
||||
}
|
||||
|
@ -403,7 +395,6 @@ export default function windows(
|
|||
|
||||
return {
|
||||
...state,
|
||||
someFullscreen: false,
|
||||
windows: newWindows,
|
||||
};
|
||||
}
|
||||
|
@ -414,23 +405,23 @@ export default function windows(
|
|||
xDiff,
|
||||
yDiff,
|
||||
} = action;
|
||||
const newWindows = state.windows.map((win) => {
|
||||
if (win.windowId !== windowId) return win;
|
||||
const [xPos, yPos] = clampPos(
|
||||
win.xPos + xDiff,
|
||||
win.yPos + yDiff,
|
||||
win.width,
|
||||
win.height,
|
||||
);
|
||||
return {
|
||||
...win,
|
||||
xPos,
|
||||
yPos,
|
||||
};
|
||||
});
|
||||
let {
|
||||
xPos, yPos,
|
||||
} = state.positions[windowId];
|
||||
const {
|
||||
width, height,
|
||||
} = state.positions[windowId];
|
||||
[xPos, yPos] = clampPos(xPos + xDiff, yPos + yDiff, width, height);
|
||||
return {
|
||||
...state,
|
||||
windows: newWindows,
|
||||
positions: {
|
||||
...state.positions,
|
||||
[windowId]: {
|
||||
...state.positions[windowId],
|
||||
xPos,
|
||||
yPos,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -440,22 +431,18 @@ export default function windows(
|
|||
xDiff,
|
||||
yDiff,
|
||||
} = action;
|
||||
const newWindows = state.windows.map((win) => {
|
||||
if (win.windowId !== windowId) return win;
|
||||
const [width, height] = clampSize(
|
||||
win.width + xDiff,
|
||||
win.height + yDiff,
|
||||
false,
|
||||
);
|
||||
return {
|
||||
...win,
|
||||
width: Math.max(width, SCREEN_MARGIN_EW - win.xPos),
|
||||
height,
|
||||
};
|
||||
});
|
||||
let { width, height } = state.positions[windowId];
|
||||
[width, height] = clampSize(width + xDiff, height + yDiff, false);
|
||||
return {
|
||||
...state,
|
||||
windows: newWindows,
|
||||
positions: {
|
||||
...state.positions,
|
||||
[windowId]: {
|
||||
...state.positions[windowId],
|
||||
width,
|
||||
height,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -466,16 +453,17 @@ export default function windows(
|
|||
innerHeight: height,
|
||||
} = window;
|
||||
|
||||
let { windows: newWindows, args, someFullscreen } = state;
|
||||
let { windows: newWindows, args, positions } = state;
|
||||
const showWindows = width > SCREEN_WIDTH_THRESHOLD;
|
||||
|
||||
if (action.type === 'RECEIVE_ME') {
|
||||
if (state.modal) {
|
||||
// reset if out of date
|
||||
if (!showWindows) {
|
||||
// reset on phones on every refresh
|
||||
return initialState;
|
||||
}
|
||||
|
||||
args = { ...state.args };
|
||||
args = { ...args };
|
||||
positions = { ...positions };
|
||||
|
||||
newWindows = newWindows.filter((win) => {
|
||||
if (win.open && (win.fullscreen || showWindows)) {
|
||||
|
@ -486,12 +474,9 @@ export default function windows(
|
|||
`Cleaning up window from previous session: ${win.windowId}`,
|
||||
);
|
||||
delete args[win.windowId];
|
||||
delete positions[win.windowId];
|
||||
return false;
|
||||
});
|
||||
|
||||
someFullscreen = newWindows.some(
|
||||
(win) => win.fullscreen && !win.hidden,
|
||||
);
|
||||
}
|
||||
|
||||
if (!showWindows) {
|
||||
|
@ -499,45 +484,47 @@ export default function windows(
|
|||
...state,
|
||||
windows: newWindows,
|
||||
showWindows,
|
||||
someFullscreen,
|
||||
args,
|
||||
positions,
|
||||
};
|
||||
}
|
||||
|
||||
const xMax = width - SCREEN_MARGIN_EW;
|
||||
const yMax = height - SCREEN_MARGIN_S;
|
||||
let modified = false;
|
||||
const fixWindows = [];
|
||||
const newPositions = {};
|
||||
|
||||
for (let i = 0; i < newWindows.length; i += 1) {
|
||||
const win = newWindows[i];
|
||||
const id = newWindows[i].windowId;
|
||||
const {
|
||||
xPos,
|
||||
yPos,
|
||||
width: winWidth,
|
||||
height: winHeight,
|
||||
} = win;
|
||||
} = positions[id];
|
||||
if (xPos > xMax || yPos > yMax
|
||||
|| width > winWidth || height > winHeight) {
|
||||
modified = true;
|
||||
fixWindows.push({
|
||||
...win,
|
||||
newPositions[id] = {
|
||||
xPos: Math.min(xMax, xPos),
|
||||
yPos: Math.min(yMax, yPos),
|
||||
width: Math.min(winWidth, width - SCREEN_MARGIN_S),
|
||||
height: Math.min(winHeight, height - SCREEN_MARGIN_S),
|
||||
});
|
||||
};
|
||||
} else {
|
||||
fixWindows.push(win);
|
||||
newPositions[id] = positions[id];
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
positions = newPositions;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
windows: (modified) ? fixWindows : newWindows,
|
||||
windows: newWindows,
|
||||
showWindows: true,
|
||||
someFullscreen,
|
||||
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,
|
||||
} = state.gui;
|
||||
const {
|
||||
requestingPixel,
|
||||
allowSettingPixel,
|
||||
} = state.user;
|
||||
const {
|
||||
view,
|
||||
|
@ -444,13 +444,13 @@ class Renderer {
|
|||
// if we have to render placeholder
|
||||
const doRenderPlaceholder = (
|
||||
viewscale >= 3
|
||||
&& requestingPixel
|
||||
&& allowSettingPixel
|
||||
&& (hover || this.hover)
|
||||
&& !isPotato
|
||||
);
|
||||
const doRenderPotatoPlaceholder = (
|
||||
viewscale >= 3
|
||||
&& requestingPixel
|
||||
&& allowSettingPixel
|
||||
&& (hover !== this.hover
|
||||
|| this.forceNextRender
|
||||
|| this.forceNextSubrender
|
||||
|
|
|
@ -398,7 +398,7 @@ class Renderer {
|
|||
store,
|
||||
} = this;
|
||||
const {
|
||||
requestingPixel,
|
||||
allowSettingPixel,
|
||||
} = store.getState().user;
|
||||
|
||||
mouse.set(
|
||||
|
@ -414,7 +414,7 @@ class Renderer {
|
|||
.add(intersect.face.normal.multiplyScalar(0.5))
|
||||
.floor()
|
||||
.addScalar(0.5);
|
||||
if (!requestingPixel
|
||||
if (!allowSettingPixel
|
||||
|| target.clone().sub(camera.position).length() > 120) {
|
||||
rollOverMesh.position.y = -10;
|
||||
} else {
|
||||
|
@ -442,7 +442,7 @@ class Renderer {
|
|||
store,
|
||||
} = this;
|
||||
const {
|
||||
requestingPixel,
|
||||
allowSettingPixel,
|
||||
} = store.getState().user;
|
||||
|
||||
mouse.set(0, 0);
|
||||
|
@ -454,9 +454,9 @@ class Renderer {
|
|||
.add(intersect.face.normal.multiplyScalar(0.5))
|
||||
.floor()
|
||||
.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
|
||||
if (!requestingPixel
|
||||
if (!allowSettingPixel
|
||||
|| target.clone().sub(camera.position).length() > 50) {
|
||||
rollOverMesh.position.y = -10;
|
||||
} else {
|
||||
|
@ -482,6 +482,7 @@ class Renderer {
|
|||
const [i, j] = getChunkOfPixel(canvasSize, x, y, z);
|
||||
const offset = getOffsetOfPixel(canvasSize, x, y, z);
|
||||
tryPlacePixel(
|
||||
this,
|
||||
store,
|
||||
i, j,
|
||||
offset,
|
||||
|
@ -578,10 +579,10 @@ class Renderer {
|
|||
|
||||
const state = this.store.getState();
|
||||
const {
|
||||
requestingPixel,
|
||||
allowSettingPixel,
|
||||
isOnMobile,
|
||||
} = state.user;
|
||||
if (!requestingPixel || isOnMobile) {
|
||||
if (!allowSettingPixel || isOnMobile) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,18 +3,19 @@
|
|||
* Always just one pixelrequest, queue additional requests to send later
|
||||
* 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 {
|
||||
notify,
|
||||
setRequestingPixel,
|
||||
setAllowSettingPixel,
|
||||
pAlert,
|
||||
gotCoolDownDelta,
|
||||
setWait,
|
||||
placedPixels,
|
||||
pixelWait,
|
||||
updatePixel,
|
||||
storeReceivePixelReturn,
|
||||
} from '../store/actions';
|
||||
import {
|
||||
notify,
|
||||
} from '../store/actions/thunks';
|
||||
import SocketClient from '../socket/SocketClient';
|
||||
|
||||
let pixelTimeout = null;
|
||||
|
@ -35,8 +36,10 @@ let clientPredictions = [];
|
|||
*/
|
||||
let lastRequestValues = {};
|
||||
|
||||
|
||||
export function requestFromQueue(store) {
|
||||
/*
|
||||
* request pixel placement from queue
|
||||
*/
|
||||
function requestFromQueue(store) {
|
||||
if (!pixelQueue.length) {
|
||||
pixelTimeout = null;
|
||||
return;
|
||||
|
@ -46,7 +49,7 @@ export function requestFromQueue(store) {
|
|||
pixelTimeout = setTimeout(() => {
|
||||
pixelQueue = [];
|
||||
pixelTimeout = null;
|
||||
store.dispatch(setRequestingPixel(true));
|
||||
store.dispatch(setAllowSettingPixel(true));
|
||||
store.dispatch(pAlert(
|
||||
t`Error :(`,
|
||||
t`Didn't get an answer from pixelplanet. Maybe try to refresh?`,
|
||||
|
@ -57,11 +60,14 @@ export function requestFromQueue(store) {
|
|||
lastRequestValues = pixelQueue.shift();
|
||||
const { i, j, pixels } = lastRequestValues;
|
||||
SocketClient.requestPlacePixels(i, j, pixels);
|
||||
store.dispatch(setRequestingPixel(false));
|
||||
store.dispatch(setAllowSettingPixel(false));
|
||||
}
|
||||
|
||||
/*
|
||||
* got pixel update from websocket
|
||||
*/
|
||||
export function receivePixelUpdate(
|
||||
store,
|
||||
renderer,
|
||||
i,
|
||||
j,
|
||||
offset,
|
||||
|
@ -79,7 +85,7 @@ export function receivePixelUpdate(
|
|||
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
|
||||
*/
|
||||
function revertPredictionsAt(
|
||||
store,
|
||||
renderer,
|
||||
sI,
|
||||
sJ,
|
||||
sOffset,
|
||||
|
@ -111,14 +117,18 @@ function revertPredictionsAt(
|
|||
|
||||
while (p < clientPredictions.length) {
|
||||
const [i, j, offset, color] = clientPredictions[p];
|
||||
store.dispatch(updatePixel(i, j, offset, color, false));
|
||||
renderer.renderPixel(i, j, offset, color, false);
|
||||
p += 1;
|
||||
}
|
||||
|
||||
clientPredictions = [];
|
||||
}
|
||||
|
||||
/*
|
||||
* try to place a pixel
|
||||
*/
|
||||
export function tryPlacePixel(
|
||||
renderer,
|
||||
store,
|
||||
i,
|
||||
j,
|
||||
|
@ -126,7 +136,7 @@ export function tryPlacePixel(
|
|||
color,
|
||||
curColor,
|
||||
) {
|
||||
store.dispatch(updatePixel(i, j, offset, color, false));
|
||||
renderer.renderPixel(i, j, offset, color, false);
|
||||
clientPredictions.push([i, j, offset, curColor, color]);
|
||||
|
||||
if (pixelQueue.length) {
|
||||
|
@ -150,28 +160,26 @@ export function tryPlacePixel(
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* got return from pixel request
|
||||
*/
|
||||
export function receivePixelReturn(
|
||||
store,
|
||||
retCode,
|
||||
wait,
|
||||
coolDownSeconds,
|
||||
pxlCnt,
|
||||
rankedPxlCnt,
|
||||
renderer,
|
||||
args,
|
||||
) {
|
||||
clearTimeout(pixelTimeout);
|
||||
|
||||
/*
|
||||
* the terms coolDown is used in a different meaning here
|
||||
* coolDown is the delta seconds of the placed pixel
|
||||
*/
|
||||
if (wait) {
|
||||
store.dispatch(setWait(wait));
|
||||
}
|
||||
store.dispatch(storeReceivePixelReturn(args));
|
||||
|
||||
const {
|
||||
retCode,
|
||||
coolDownSeconds,
|
||||
pxlCnt,
|
||||
} = args;
|
||||
|
||||
if (coolDownSeconds) {
|
||||
store.dispatch(notify(coolDownSeconds));
|
||||
if (coolDownSeconds < 0) {
|
||||
store.dispatch(gotCoolDownDelta(coolDownSeconds));
|
||||
}
|
||||
}
|
||||
|
||||
if (retCode) {
|
||||
|
@ -181,7 +189,7 @@ export function receivePixelReturn(
|
|||
*/
|
||||
const { i, j, pixels } = lastRequestValues;
|
||||
const [offset] = pixels[pxlCnt];
|
||||
revertPredictionsAt(store, i, j, offset);
|
||||
revertPredictionsAt(renderer, i, j, offset);
|
||||
pixelQueue = [];
|
||||
}
|
||||
|
||||
|
@ -190,7 +198,6 @@ export function receivePixelReturn(
|
|||
let type = 'error';
|
||||
switch (retCode) {
|
||||
case 0:
|
||||
store.dispatch(placedPixels(rankedPxlCnt));
|
||||
break;
|
||||
case 1:
|
||||
errorTitle = t`Invalid Canvas`;
|
||||
|
@ -226,7 +233,6 @@ export function receivePixelReturn(
|
|||
break;
|
||||
case 9:
|
||||
// pixestack used up
|
||||
store.dispatch(pixelWait());
|
||||
break;
|
||||
case 10:
|
||||
errorTitle = 'Captcha';
|
||||
|
@ -267,11 +273,6 @@ export function receivePixelReturn(
|
|||
));
|
||||
}
|
||||
|
||||
store.dispatch(setRequestingPixel(true));
|
||||
|
||||
if (!msg) {
|
||||
/* start next request if queue isn't empty */
|
||||
requestFromQueue(store);
|
||||
}
|
||||
requestFromQueue(store);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user