Compare commits

..

No commits in common. "bb1d9f71a8f5609c7e47ae20493982683286d08a" and "e63f351f63948f7cae3ca6b4391246b463b14ff5" have entirely different histories.

21 changed files with 581 additions and 1143 deletions

3
.gitignore vendored
View File

@ -93,6 +93,3 @@ out/
# WebStorm # WebStorm
.idea/ .idea/
# Data Directory
data/

188
package-lock.json generated
View File

@ -14,12 +14,10 @@
"@fontsource/roboto": "^5.0.12", "@fontsource/roboto": "^5.0.12",
"@mui/icons-material": "^5.15.14", "@mui/icons-material": "^5.15.14",
"@mui/material": "^5.15.14", "@mui/material": "^5.15.14",
"@types/websocket": "^1.0.10",
"electron-squirrel-startup": "^1.0.0", "electron-squirrel-startup": "^1.0.0",
"node-wifi-scanner": "git+https://git.gaminggeneration.de/tobiash/node-wifi-scanner", "node-wifi-scanner": "git+https://git.gaminggeneration.de/tobiash/node-wifi-scanner",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0"
"websocket": "^1.0.34"
}, },
"devDependencies": { "devDependencies": {
"@electron-forge/cli": "^7.3.1", "@electron-forge/cli": "^7.3.1",
@ -1955,6 +1953,7 @@
"version": "20.11.30", "version": "20.11.30",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz",
"integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
@ -2101,14 +2100,6 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/websocket": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.10.tgz",
"integrity": "sha512-svjGZvPB7EzuYS94cI7a+qhwgGU1y89wUgjT6E2wVUfmAGIvRfT7obBvRtnhXCSsoMdlG4gBFGE7MfkIXZLoww==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.5.10", "version": "8.5.10",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
@ -3221,18 +3212,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/bufferutil": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz",
"integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
"hasInstallScript": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -3990,18 +3969,6 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
}, },
"node_modules/d": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz",
"integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
"dependencies": {
"es5-ext": "^0.10.64",
"type": "^2.7.2"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/data-view-buffer": { "node_modules/data-view-buffer": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
@ -4906,21 +4873,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/es5-ext": {
"version": "0.10.64",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
"integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
"hasInstallScript": true,
"dependencies": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
"esniff": "^2.0.1",
"next-tick": "^1.1.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/es6-error": { "node_modules/es6-error": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
@ -4929,28 +4881,6 @@
"license": "MIT", "license": "MIT",
"optional": true "optional": true
}, },
"node_modules/es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
"dependencies": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"node_modules/es6-symbol": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz",
"integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
"dependencies": {
"d": "^1.0.2",
"ext": "^1.7.0"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/escalade": { "node_modules/escalade": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
@ -5228,20 +5158,6 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/esniff": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
"integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
"dependencies": {
"d": "^1.0.1",
"es5-ext": "^0.10.62",
"event-emitter": "^0.3.5",
"type": "^2.7.2"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/espree": { "node_modules/espree": {
"version": "9.6.1", "version": "9.6.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
@ -5316,15 +5232,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
"dependencies": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"node_modules/eventemitter3": { "node_modules/eventemitter3": {
"version": "4.0.7", "version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
@ -5555,14 +5462,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/ext": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
"dependencies": {
"type": "^2.7.2"
}
},
"node_modules/extract-zip": { "node_modules/extract-zip": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
@ -7301,11 +7200,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"node_modules/is-unicode-supported": { "node_modules/is-unicode-supported": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
@ -8286,11 +8180,6 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/next-tick": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
},
"node_modules/nice-try": { "node_modules/nice-try": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@ -8396,16 +8285,6 @@
"node": "^12.13 || ^14.13 || >=16" "node": "^12.13 || ^14.13 || >=16"
} }
}, },
"node_modules/node-gyp-build": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz",
"integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==",
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/node-loader": { "node_modules/node-loader": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/node-loader/-/node-loader-2.0.0.tgz", "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-2.0.0.tgz",
@ -11190,11 +11069,6 @@
"dev": true, "dev": true,
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/type": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
"integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
},
"node_modules/type-check": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -11312,14 +11186,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/typedarray-to-buffer": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
"dependencies": {
"is-typedarray": "^1.0.0"
}
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.5.5", "version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
@ -11354,6 +11220,7 @@
"version": "5.26.5", "version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/unique-filename": { "node_modules/unique-filename": {
@ -11457,18 +11324,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/utf-8-validate": {
"version": "5.0.10",
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
"hasInstallScript": true,
"dependencies": {
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=6.14.2"
}
},
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -11879,22 +11734,6 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/websocket": {
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
"integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
"dependencies": {
"bufferutil": "^4.0.1",
"debug": "^2.2.0",
"es5-ext": "^0.10.50",
"typedarray-to-buffer": "^3.1.5",
"utf-8-validate": "^5.0.2",
"yaeti": "^0.0.6"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/websocket-driver": { "node_modules/websocket-driver": {
"version": "0.7.4", "version": "0.7.4",
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
@ -11920,19 +11759,6 @@
"node": ">=0.8.0" "node": ">=0.8.0"
} }
}, },
"node_modules/websocket/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/websocket/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/whatwg-url": { "node_modules/whatwg-url": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
@ -12108,14 +11934,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/yaeti": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
"integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==",
"engines": {
"node": ">=0.10.32"
}
},
"node_modules/yallist": { "node_modules/yallist": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

View File

@ -1,36 +1,21 @@
import {w3cwebsocket, IMessageEvent} from "websocket"; import {client as WebSocketClient, connection} from "websocket";
export default class CloudHandler { export default class CloudHandler {
private static websocket = new WebSocketClient();
private static connection: connection;
private static connection: w3cwebsocket;
static connect() { static connect() {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
this.connection = new w3cwebsocket('wss://smartmonopoly.iif.li'); this.websocket.connect("ws://smartmonopoly.iif.li");
this.connection.onerror = (err: Error) => { this.websocket.on("connectFailed", (err) => {
this.connection = null;
reject(err); reject(err);
};
this.connection.onopen = () => {
resolve();
};
this.connection.onclose = () => {
this.connection = null;
}
this.connection.onmessage = (e) => this.handleMessage(e);
}); });
} this.websocket.on("connect", (connection) => {
this.connection = connection;
private static handleMessage(e: IMessageEvent) resolve();
{ });
});
} }
static isConnected(): boolean {
return !!this.connection;
}
} }

View File

@ -1,58 +0,0 @@
import path from "path";
import process from "process";
import * as fs from "fs";
import {Config, GameRules} from "./RawConstants";
export class ConfigHandler {
private static defaultConfig = {
rules: {
switchValues: {},
inputValues: {}
}
}
private static confPath = path.resolve(process.cwd(), "data", "config.json");
static generateDefault() {
fs.writeFileSync(this.confPath, JSON.stringify(this.defaultConfig, null, 1));
}
static get() {
if(!fs.existsSync(this.confPath))
this.generateDefault();
let confRaw = fs.readFileSync(this.confPath).toString('utf8');
try {
JSON.parse(confRaw);
}catch(e)
{
this.generateDefault();
}
console.log("Config retrieved!")
return JSON.parse(confRaw) as Config;
}
static set(conf: Config) {
if(!fs.existsSync(this.confPath))
this.generateDefault();
let confRaw = fs.readFileSync(this.confPath).toString('utf8');
try {
JSON.parse(confRaw);
}catch(e)
{
this.generateDefault();
}
let current = JSON.parse(confRaw) as Config;
current = {...current, ...conf};
console.log("Config saved!")
fs.writeFileSync(this.confPath, JSON.stringify(current, null, 1));
}
}

34
src/IPCConstants.ts Normal file
View File

@ -0,0 +1,34 @@
export type IPCChannel =
'WIFI_STATUS'
| 'WIFI_SCAN'
| 'WIFI_LIST'
| 'WIFI_CONNECT'
| 'FUNCTION_TEST'
| 'CLOUD_STATUS'
| 'CLOUD_CONNECT'
export interface IPCAnswer {
status: boolean,
data?: any
}
export interface IPCRequest {
data?: any,
}
export interface WiFiNetwork {
ssid: string,
isSecured: boolean,
isKnown?: boolean,
psk?: string,
rssi?: number,
}
export interface FunctionTest {
hasSudo: boolean,
hasWPASupplicant: boolean,
hasInternet: boolean
}

View File

@ -1,6 +1,6 @@
import { ipcMain } from 'electron'; import { ipcMain } from 'electron';
import IpcMainInvokeEvent = Electron.IpcMainInvokeEvent; import IpcMainInvokeEvent = Electron.IpcMainInvokeEvent;
import {IPCAnswer, IPCChannel, IPCRequest} from "./RawConstants"; import {IPCAnswer, IPCChannel, IPCRequest} from "./IPCConstants";
export const IPCHandler = ( export const IPCHandler = (

View File

@ -1,4 +1,4 @@
import {WiFiNetwork} from "./RawConstants"; import {WiFiNetwork} from "./IPCConstants";
import {spawn, exec} from 'node:child_process'; import {spawn, exec} from 'node:child_process';
import * as dns from "dns"; import * as dns from "dns";
import * as process from "process"; import * as process from "process";

View File

@ -1,106 +0,0 @@
export type IPCChannel =
'WIFI_SCAN'
| 'WIFI_CONNECT'
| 'FUNCTION_TEST'
| 'CLOUD_STATUS'
| 'CLOUD_CONNECT'
| 'SETTINGS'
| 'PREPARING'
export enum IPCListenChannels {
'KEYPAD_INPUT'= 'KEYPAD_INPUT',
'NFC_CARD'= 'NFC_CARD',
'NFC_RAW' = 'NFC_RAW'
}
export interface IPCAnswer {
status: boolean,
data?: any
}
export interface IPCRequest {
data?: any,
}
export interface WiFiNetwork {
ssid: string,
isSecured: boolean,
isKnown?: boolean,
psk?: string,
rssi?: number,
}
export interface FunctionTest {
hasSudo: boolean,
hasWPASupplicant: boolean,
hasInternet: boolean
}
export type GameSwitch = {
name: GameSwitchNames,
label: string,
depends?: GameSwitchNames,
value: boolean
}
export type GameInput = {
name: GameInputNames,
type: "number" | "string",
label: string,
depends?: GameSwitchNames,
value: string
}
export type GameSwitchNames =
"GET_BONUS_PASSING_START"
| "DOUBLE_BONUS_ON_GO"
| "PUT_PAID_PENALTIES_IN_MIDDLE"
| "RECEIVE_PENALTIES_AT_FREE_PARKING"
| "PUT_10_IN_MIDDLE_AFTER_EACH_GO"
| "STREET_MUST_BE_AUCTIONED_IF_NOT_PURCHASED"
| "TWO_HOTELS_PER_STREET_ALLOWED"
| "MORTGAGE_REDUCES_RENT"
| "GOODS_GO_TO_OTHER_PLAYERS_UPON_BANKRUPTCY"
| "STREETS_CAN_BE_SOLD_BACK_TO_THE_BANK"
| "PRISON_CAN_BE_PURCHASED_RENT_GOES_TO_PLAYER"
| "KEEP_MONEY_MORE_SECRET";
export type GameInputNames =
"PASSING_GO_CASH"
| "STARTING_CASH"
| "PRISON_RELEASE_FEE";
export interface GameRules {
switchValues: { [key in GameSwitchNames]?: boolean },
inputValues: { [key in GameInputNames]?: string }
}
export interface Config {
rules?: GameRules
}
export enum NFCCardType {
ACCOUNT,
PROPERTY,
TASK,
}
export interface NFCCard {
cardType: NFCCardType,
uid: string,
raw: string
}
export interface NFCAccountCard extends NFCCard {
symbol: string,
friendlyName: string,
pin: number
}
export interface NFCPropertyCard extends NFCCard {
}
export interface NFCTaskCard extends NFCCard {
}

View File

@ -1,8 +1,7 @@
import {IPCHandler} from "./IPCHandler"; import {IPCHandler} from "./IPCHandler";
import {FunctionTest, GameRules} from "./RawConstants"; import {FunctionTest, WiFiNetwork} from "./IPCConstants";
import OSHandler from "./OSHandler"; import OSHandler from "./OSHandler";
import CloudHandler from "./CloudHandler"; import CloudHandler from "./CloudHandler";
import {ConfigHandler} from "./ConfigHandler";
const wifiScan = require("node-wifi-scanner"); const wifiScan = require("node-wifi-scanner");
@ -41,7 +40,7 @@ export default class SmartMonopoly {
} }
}); });
IPCHandler("WIFI_SCAN", async (e, request) => { IPCHandler("WIFI_SCAN", async (e, request, args) => {
try { try {
let networks = await OSHandler.scanWifis(); let networks = await OSHandler.scanWifis();
return {status: true, data: networks}; return {status: true, data: networks};
@ -50,39 +49,13 @@ export default class SmartMonopoly {
} }
}); });
IPCHandler("CLOUD_CONNECT", async (e, request) => { IPCHandler("CLOUD_CONNECT", async (e, request, args) => {
try { try {
await CloudHandler.connect(); await CloudHandler.connect();
return {status: true} return {status: true}
} catch (e) { } catch (e) {
return {status: false, data: e}; return {status: false, data: e};
} }
});
IPCHandler("SETTINGS", async(e, request) => {
if(request.data && request.data["rules"])
{
let rules = request.data.rules as GameRules;
ConfigHandler.set({rules: rules});
}
return {status: true, data: ConfigHandler.get()};
});
IPCHandler("PREPARING", async(e, request) => {
const useCloud = !!request.data.useCloud;
console.log("Preparing - useCloud: " + useCloud);
if(useCloud && !CloudHandler.isConnected())
try {
await CloudHandler.connect();
}catch(e)
{
return {status: false, data: 'Cloud connection issue: ' + e};
}
//todo when using cloud, get session etc.
return {status: true};
}) })
} }
} }

View File

@ -2,7 +2,7 @@
// https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts // https://www.electronjs.org/docs/latest/tutorial/process-model#preload-scripts
import {ipcRenderer, contextBridge} from 'electron'; import {ipcRenderer, contextBridge} from 'electron';
import {IPCAnswer, IPCChannel, IPCRequest} from "./RawConstants"; import {IPCAnswer, IPCChannel, IPCRequest} from "./IPCConstants";
import IpcRendererEvent = Electron.IpcRendererEvent; import IpcRendererEvent = Electron.IpcRendererEvent;
contextBridge.exposeInMainWorld('api', { contextBridge.exposeInMainWorld('api', {

View File

@ -2,6 +2,7 @@ import {createRoot} from 'react-dom/client';
import React, {Component} from "react"; import React, {Component} from "react";
import Startup from "./Startup"; import Startup from "./Startup";
import WiFi from "./WiFi"; import WiFi from "./WiFi";
import Cloud from "./Cloud";
import Game from "./Game"; import Game from "./Game";
import GameSetup from "./GameSetup"; import GameSetup from "./GameSetup";
import GameEnd from "./GameEnd"; import GameEnd from "./GameEnd";
@ -9,8 +10,58 @@ import Setup from "./Setup";
const root = createRoot(document.getElementById("root")); const root = createRoot(document.getElementById("root"));
//window.app = window.MyNamespace || {};
export enum PAGE {
interface HeadingSwitcherState {
counter: number;
}
class HeadingSwitcher extends Component<{}, HeadingSwitcherState> {
private interval: NodeJS.Timeout;
constructor(props: {}) {
super(props);
this.state = {counter: 0};
}
componentDidMount() {
this.interval = setInterval(() => this.tick(), 500);
}
componentWillUnmount() {
clearInterval(this.interval);
}
tick() {
if (this.state.counter > 5)
this.setState({counter: 1});
else
this.setState({counter: this.state.counter + 1});
}
render() {
switch (this.state.counter) {
case 1:
return <h1>H1</h1>;
case 2:
return <h2>H2</h2>;
case 3:
return <h3>H3</h3>;
case 4:
return <h4>H4</h4>;
case 5:
return <h5>H5</h5>;
case 6:
return <h6>H6</h6>;
}
}
}
enum PAGE {
STARTUP, STARTUP,
SETUP, SETUP,
WIFI, WIFI,
@ -32,7 +83,7 @@ export class App extends Component<{}, AppState> {
constructor(props: {}) { constructor(props: {}) {
super(props); super(props);
this.state = { this.state = {
currentPage: PAGE.GAME_SETUP, currentPage: PAGE.SETUP,
showWiFi: false, showWiFi: false,
} }
} }
@ -51,13 +102,6 @@ export class App extends Component<{}, AppState> {
})); }));
} }
public setPage = (page: PAGE) => {
this.setState((prevState) => ({
...prevState,
currentPage: page
}));
}
render() { render() {
@ -65,7 +109,7 @@ export class App extends Component<{}, AppState> {
<div className="app"> <div className="app">
{this.state.showWiFi ? <WiFi/> : null} {this.state.showWiFi ? <WiFi/> : null}
{this.state.currentPage == PAGE.STARTUP || this.state.currentPage == PAGE.SETUP ? <Startup visible={this.state.currentPage == PAGE.STARTUP} ref={(ref) => { {this.state.currentPage == PAGE.STARTUP ? <Startup ref={(ref) => {
App.PAGES.set(PAGE.STARTUP, ref); App.PAGES.set(PAGE.STARTUP, ref);
}}/> : null} }}/> : null}
@ -73,6 +117,14 @@ export class App extends Component<{}, AppState> {
App.PAGES.set(PAGE.SETUP, ref); App.PAGES.set(PAGE.SETUP, ref);
}}/> : null} }}/> : null}
{this.state.currentPage == PAGE.WIFI ? <WiFi ref={(ref) => {
App.PAGES.set(PAGE.WIFI, ref);
}}/> : null}
{this.state.currentPage == PAGE.CLOUD ? <Cloud ref={(ref) => {
App.PAGES.set(PAGE.CLOUD, ref);
}}/> : null}
{this.state.currentPage == PAGE.GAME_SETUP ? <GameSetup ref={(ref) => { {this.state.currentPage == PAGE.GAME_SETUP ? <GameSetup ref={(ref) => {
App.PAGES.set(PAGE.GAME_SETUP, ref); App.PAGES.set(PAGE.GAME_SETUP, ref);
}}/> : null} }}/> : null}

25
src/web/Cloud.tsx Normal file
View File

@ -0,0 +1,25 @@
import {Component} from "react";
interface CloudState {
}
export default class Cloud extends Component<{}, CloudState> {
constructor(props: {}) {
super(props);
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return <p>Test</p>
}
}

View File

@ -1,64 +0,0 @@
import {PAGE} from "./App";
import {IPCListenChannels, NFCCard} from "../RawConstants";
import IPCListener from "./IPCListener";
export enum GAME_STATE {
NOT_STARTED,
PREPARING,
PLAYING,
END
}
export default class GameHandler {
static GAMESTATE: GAME_STATE = GAME_STATE.NOT_STARTED;
static attachedNFCHandler: number = 0;
static setGameState(state: GAME_STATE)
{
switch (state)
{
case GAME_STATE.NOT_STARTED:
window.app.setPage(PAGE.STARTUP);
break;
case GAME_STATE.PREPARING :
window.app.setPage(PAGE.GAME_SETUP);
break;
}
this.GAMESTATE = state;
}
static attachNFCHandler(cb: (card: NFCCard) => void)
{
IPCListener.detach(this.attachedNFCHandler);
this.attachedNFCHandler = IPCListener.attach(IPCListenChannels.NFC_CARD, (ipcMsg) => {
if(ipcMsg.status)
cb(ipcMsg.data as NFCCard);
});
}
static detachNFCHandler()
{
IPCListener.detach(this.attachedNFCHandler);
}
static async requestPreparing(useCloud: boolean)
{
let response = await window.api.request("PREPARING", {
data:
{
useCloud: useCloud,
}
});
if(!response.status)
{
this.setGameState(GAME_STATE.NOT_STARTED);
throw new Error(response.data);
}
this.setGameState(GAME_STATE.PREPARING);
return true;
}
}

View File

@ -1,103 +1,26 @@
import {Component} from "react"; import {Component} from "react";
import {
Button, Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Grid,
Snackbar,
Typography
} from "@mui/material";
import NfcIcon from '@mui/icons-material/Nfc';
import AddCardIcon from '@mui/icons-material/AddCard';
import PersonAddIcon from '@mui/icons-material/PersonAdd';
import PersonRemoveIcon from '@mui/icons-material/PersonRemove';
import GameHandler from "./GameHandler";
import {NFCCard} from "../RawConstants";
interface GameState { interface GameState {
snackMsg: string,
helpDialog: boolean
} }
export default class GameSetup extends Component<{}, GameState> { export default class GameSetup extends Component<{}, GameState> {
constructor(props: {}) { constructor(props: {}) {
super(props); super(props);
this.state = {
snackMsg: "",
helpDialog: true
}
} }
componentDidMount() { componentDidMount() {
setTimeout(() => {
this.setState((prevState) => ({
...prevState,
helpDialog: false,
snackMsg: "Zum hinzufügen von Spielern, NFC-Karte an das Lesegerät halten!",
}))
}, 15000);
GameHandler.attachNFCHandler((card: NFCCard) => {
})
} }
componentWillUnmount() { componentWillUnmount() {
GameHandler.detachNFCHandler();
} }
render() { render() {
return <div className="gameSetup"> return <p>Test</p>
<Snackbar
open={!!this.state.snackMsg}
autoHideDuration={8000}
onClose={() => {
this.setState(prevState => ({
...prevState,
snackMsg: ""
}))
}}
message={this.state.snackMsg}
/>
<Dialog
open={this.state.helpDialog}
onClose={() => {
this.setState((prevState) => ({
...prevState,
helpDialog: false
}))
}}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
Karte anhalten, um Spieler hinzuzufügen! <AddCardIcon/>
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Um eine Figur zum Spiel hinzuzufügen, musst du die NFC-Spielerkarte an den Kartenleser
halten. <br/><br/>
Ein kurzes Berühren reicht aus, schon sollte der Spieler in der Tabelle auftauchen! <PersonAddIcon/>
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => this.setState((prevState) => ({
...prevState,
helpDialog: false
}))}>
Okay</Button>
</DialogActions>
</Dialog>
<Typography variant="h2" sx={{mb: 2}}>Wer spielt mit?</Typography>
<Grid container spacing={3}>
</Grid>
</div>
} }
} }

View File

@ -1,36 +0,0 @@
import {IPCAnswer, IPCListenChannels} from "../RawConstants";
type IPCListen = {
channel: IPCListenChannels,
fn: (message: IPCAnswer, ...args: any) => void,
}
export default class IPCListener {
private static attachments: Map<number, IPCListen> = new Map<number, IPCListen>();
private static uID = 99;
public static attach(event: IPCListenChannels, fn: (message: IPCAnswer, ...args: any) => void): number {
this.uID++;
this.attachments.set(this.uID, {fn: fn, channel: event});
return this.uID;
}
public static detach(id: number)
{
this.attachments.delete(id);
}
public static initialAttach()
{
for(let c of Object.keys(IPCListenChannels))
{
window.api.listen((c as unknown as IPCListenChannels), (event, message: IPCAnswer, ...args: any) => {
for(let [a, listener] of this.attachments)
{
listener.fn(message, ...args);
}
});
}
}
}

View File

@ -1,31 +1,44 @@
import React, {Component} from "react"; import React, {Component} from "react";
import { import {FormControl, FormControlLabel, FormGroup, FormLabel, Grid, Switch} from "@mui/material";
Button,
FormControl, type GameSwitch = {
FormControlLabel, name: GameSwitchNames,
FormGroup, label: string,
FormLabel, depends?: GameSwitchNames,
Grid, Snackbar, value: boolean
Switch, }
TextField,
Typography type GameSwitchNames =
} from "@mui/material"; "GET_BONUS_PASSING_START"
import RestartAltIcon from '@mui/icons-material/RestartAlt'; | "DOUBLE_BONUS_ON_GO"
import CloseIcon from '@mui/icons-material/Close'; | "PUT_PAID_PENALTIES_IN_MIDDLE"
import SaveIcon from '@mui/icons-material/Save'; | "RECEIVE_PENALTIES_AT_FREE_PARKING"
import {PAGE} from "./App"; | "PUT_10_IN_MIDDLE_AFTER_EACH_GO"
import {GameInput, GameSwitch, GameRules, GameSwitchNames, GameInputNames, Config} from "../RawConstants"; | "STREET_MUST_BE_AUCTIONED_IF_NOT_PURCHASED"
| "TWO_HOTELS_PER_STREET_ALLOWED"
| "NO_MORTGAGE_ON_STREETS_WITH_BUILDINGS"
| "MORTGAGE_REDUCES_RENT"
| "GOODS_GO_TO_OTHER_PLAYERS_UPON_BANKRUPTCY"
| "STREETS_CAN_BE_SOLD_BACK_TO_THE_BANK"
| "PRISON_CAN_BE_PURCHASED_RENT_GOES_TO_PLAYER";
type GameInputs = {
"PASSING_GO_CASH": string,
"STARTING_CASH": string,
"PRISON_RELEASE_FEE": string
}
interface InitialSetupState { interface InitialSetupState {
open: boolean, open: boolean,
switchValues: GameSwitch[], switchValues: GameSwitch[],
inputValues: GameInput[], inputValues: GameInputs
savedMsg: boolean
} }
const defaultConf: InitialSetupState = { export default class Setup extends Component<{}, InitialSetupState> {
constructor(props: {}) {
super(props);
this.state = {
open: true, open: true,
savedMsg: false,
switchValues: [ switchValues: [
{ {
name: "GET_BONUS_PASSING_START", name: "GET_BONUS_PASSING_START",
@ -45,7 +58,7 @@ const defaultConf: InitialSetupState = {
}, },
{ {
name: "RECEIVE_PENALTIES_AT_FREE_PARKING", name: "RECEIVE_PENALTIES_AT_FREE_PARKING",
label: "Bei 'Frei Parken' Strafen aus der 'Mitte' einziehen", label: "Bei 'Frei Parken' erhaltene Strafen",
depends: "PUT_PAID_PENALTIES_IN_MIDDLE", depends: "PUT_PAID_PENALTIES_IN_MIDDLE",
value: true value: true
}, },
@ -65,6 +78,11 @@ const defaultConf: InitialSetupState = {
label: "Zwei Hotels pro Straße erlaubt", label: "Zwei Hotels pro Straße erlaubt",
value: false value: false
}, },
{
name: "NO_MORTGAGE_ON_STREETS_WITH_BUILDINGS",
label: "Keine Hypothek auf Straßen mit Bauten",
value: true
},
{ {
name: "MORTGAGE_REDUCES_RENT", name: "MORTGAGE_REDUCES_RENT",
label: "Hypothek verringert Miete", label: "Hypothek verringert Miete",
@ -84,52 +102,14 @@ const defaultConf: InitialSetupState = {
name: "PRISON_CAN_BE_PURCHASED_RENT_GOES_TO_PLAYER", name: "PRISON_CAN_BE_PURCHASED_RENT_GOES_TO_PLAYER",
label: "Gefängnis kann erworben werden, Miete geht an den Spieler", label: "Gefängnis kann erworben werden, Miete geht an den Spieler",
value: false value: false
},
{
name: "KEEP_MONEY_MORE_SECRET",
label: "Geld von anderen Spielern ungenauer anzeigen",
value: false
} }
], ],
inputValues: [ inputValues: {
{ "PASSING_GO_CASH": "200",
name: "STARTING_CASH", "STARTING_CASH": "1500",
type: "number", "PRISON_RELEASE_FEE": "50"
label: "Start Guthaben",
value: "1500"
},
{
name: "PASSING_GO_CASH",
type: "number",
label: "Lohn über Los",
value: "200"
},
{
name: "PRISON_RELEASE_FEE",
type: "number",
label: "Gefängnis Gebühren",
value: "50"
}
]
}
export default class Setup extends Component<{}, InitialSetupState> {
constructor(props: {}) {
super(props);
this.state = {
...defaultConf,
} }
} }
reset = () => {
this.setState(prevState => ({
...prevState,
...defaultConf
}))
//window.api.request("")
} }
style = { style = {
@ -161,94 +141,8 @@ export default class Setup extends Component<{}, InitialSetupState> {
})); }));
} }
onInput = (event: React.ChangeEvent<HTMLInputElement>) => {
const {name, value} = event.target;
this.setState((prevState) => ({
...prevState,
inputValues: prevState.inputValues.map((switchObj) => {
if (switchObj.name === name) {
return {
...switchObj,
value: value
};
}
return switchObj;
})
}));
}
getSettings = () => {
return new Promise<void>((resolve, reject) => {
window.api.request("SETTINGS", {}).then(answer => {
try {
let data = answer.data as Config;
for (let [sw, state] of Object.entries(data.rules.switchValues)) {
this.setState((prevState) => ({
...prevState,
switchValues: prevState.switchValues.map((obj) => {
if (obj.name === sw) {
return {
...obj,
value: state
};
}
return obj;
})
}));
}
for (let [sw, state] of Object.entries(data.rules.inputValues)) {
this.setState((prevState) => ({
...prevState,
inputValues: prevState.inputValues.map((obj) => {
if (obj.name === sw) {
return {
...obj,
value: state
};
}
return obj;
})
}));
}
resolve();
} catch(e)
{
reject(e);
}
})
})
}
saveSettings = (silent = false) => {
let gameSettings: any = {
switchValues: {},
inputValues: {}
};
for (let ele of this.state.switchValues) {
gameSettings.switchValues[ele.name] = ele.value;
if(!!ele.depends && ele.value)
gameSettings.switchValues[ele.name] = this.checkDependsValue(ele.depends);
}
for (let ele of this.state.inputValues) {
gameSettings.inputValues[ele.name] = ele.value;
}
window.api.request("SETTINGS", {data: {rules: gameSettings as GameRules}}).then();
if (!silent)
this.setState(prevState => ({
...prevState,
savedMsg: true
}));
}
componentDidMount() { componentDidMount() {
this.getSettings().then();
} }
componentWillUnmount() { componentWillUnmount() {
@ -259,8 +153,9 @@ export default class Setup extends Component<{}, InitialSetupState> {
window.app.toggleWiFiSettings(false); window.app.toggleWiFiSettings(false);
} }
checkDependsValue = (depends: GameSwitchNames) => { checkDependsValue = (depends: string) => {
for (let x of this.state.switchValues) { for(let x of this.state.switchValues)
{
if(x.name == depends) if(x.name == depends)
return x.value; return x.value;
} }
@ -268,31 +163,16 @@ export default class Setup extends Component<{}, InitialSetupState> {
render() { render() {
return <div className="setup"> return <div className="setup">
<Snackbar <Grid container spacing={2}>
open={this.state.savedMsg}
autoHideDuration={6000}
onClose={() => {
this.setState(prevState => ({
...prevState,
savedMsg: false
}))
}}
message={"Einstellungen gespeichert!"}
/>
<Typography variant="h2" sx={{mb: 2}}>Einstellungen</Typography>
<Grid container spacing={3}>
<Grid item xs={6}> <Grid item xs={6}>
<FormControl component="fieldset" variant="standard"> <FormControl component="fieldset" variant="standard">
<FormLabel component="legend">Schalter-Regeln</FormLabel> <FormLabel component="legend">Regeln</FormLabel>
<FormGroup> <FormGroup>
{Object.values(this.state.switchValues).map(value => { {Object.values(this.state.switchValues).map(value => {
return ( return (
<FormControlLabel sx={{mb: 1}} <FormControlLabel sx={{mb: 1}}
control={ control={
<Switch <Switch checked={(value.value && !value.depends) || (value.value && !!value.depends && this.checkDependsValue(value.depends))} disabled={!!value.depends && !this.checkDependsValue(value.depends)} onChange={this.onSwitch}
checked={(value.value && !value.depends) || (value.value && !!value.depends && this.checkDependsValue(value.depends))}
disabled={!!value.depends && !this.checkDependsValue(value.depends)}
onChange={this.onSwitch}
name={value.name}/> name={value.name}/>
} label={value.label} } label={value.label}
/>) />)
@ -302,36 +182,13 @@ export default class Setup extends Component<{}, InitialSetupState> {
</Grid> </Grid>
<Grid item xs={6}> <Grid item xs={6}>
<FormControl component="fieldset" variant="standard"> <FormControl component="fieldset" variant="standard">
<FormLabel component="legend">Werte-Regeln</FormLabel> <FormLabel component="legend">Standardwerte</FormLabel>
<FormGroup> <FormGroup>
{Object.values(this.state.inputValues).map(value => {
return (
<FormControlLabel sx={{mb: 2}}
control={
<TextField type={value.type} variant="standard"
value={value.value}
disabled={!!value.depends && !this.checkDependsValue(value.depends)}
onChange={this.onInput}
name={value.name}/>
} label={value.label}
/>)
})}
</FormGroup> </FormGroup>
</FormControl> </FormControl>
</Grid> </Grid>
<Grid item xs={3.5}></Grid>
<Grid item xs={"auto"} alignItems="center">
<Button variant="contained" color="secondary" onClick={() => {
this.getSettings().then(r => window.app.setPage(PAGE.STARTUP));
}}>Abbrechen <CloseIcon/></Button>
<Button sx={{ml: 2}} variant="outlined" color="error"
onClick={() => this.reset()}>Zurücksetzen <RestartAltIcon/></Button>
<Button sx={{ml: 2}} variant="contained" color="success" onClick={() => {
this.saveSettings(); window.app.setPage(PAGE.STARTUP);
}}>Speichern <SaveIcon/></Button>
</Grid> </Grid>
</Grid>
</div> </div>
} }

View File

@ -2,53 +2,41 @@ import React, {Component} from "react";
import { import {
Backdrop, Backdrop,
Box, Box,
Button,
Chip,
CircularProgress, CircularProgress,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Fade, Fade,
FormControl,
Modal, Modal,
Snackbar,
Stack, Stack,
Typography, Zoom Typography,
Button,
Dialog,
DialogTitle, DialogContent, DialogContentText, DialogActions, Chip, FormControl, Snackbar
} from "@mui/material"; } from "@mui/material";
import {FunctionTest} from "../RawConstants"; import {FunctionTest} from "../IPCConstants";
import SettingsIcon from '@mui/icons-material/Settings'; import SettingsIcon from '@mui/icons-material/Settings';
import PlayCircleIcon from '@mui/icons-material/PlayCircle'; import PlayCircleIcon from '@mui/icons-material/PlayCircle';
import CloudOffIcon from '@mui/icons-material/CloudOff'; import CloudOffIcon from '@mui/icons-material/CloudOff';
import CloudIcon from '@mui/icons-material/Cloud'; import CloudIcon from '@mui/icons-material/Cloud';
import {PAGE} from "./App";
import GameHandler from "./GameHandler";
interface StartupProps {
visible: boolean
}
interface StartupState { interface StartupState {
statusTxt: string, statusTxt: string,
openCloudConnectModal: boolean, openCloudConnectModal: boolean,
showStartBtn: boolean, showStartBtn: boolean,
isCloudConnected: boolean, isConnected: boolean,
snackErrorMsg: string, cloudErrorMsg: string,
isConnectionIssue: boolean, isConnectionIssue: boolean,
startCounter: number, startCounter: number,
} }
export default class Startup extends Component<StartupProps, StartupState> { export default class Startup extends Component<{}, StartupState> {
constructor(props: StartupProps) { constructor(props: {}) {
super(props); super(props);
this.state = { this.state = {
statusTxt: "Smart-Monopoly wird gestartet...", statusTxt: "Smart-Monopoly wird gestartet...",
openCloudConnectModal: false, openCloudConnectModal: false,
showStartBtn: false, showStartBtn: false,
isCloudConnected: false, isConnected: false,
isConnectionIssue: false, isConnectionIssue: false,
snackErrorMsg: "", cloudErrorMsg: "",
startCounter: 10, startCounter: 10,
}; };
} }
@ -74,9 +62,7 @@ export default class Startup extends Component<StartupProps, StartupState> {
let response = await window.api.request("CLOUD_CONNECT", {}); let response = await window.api.request("CLOUD_CONNECT", {});
this.setState((prevState) => ({ this.setState((prevState) => ({
...prevState, ...prevState,
snackErrorMsg: response.data.toString(), cloudErrorMsg: response.data.toString()
isCloudConnected: response.status,
isConnectionIssue: !response.status,
})); }));
console.log(response) console.log(response)
return response.status; return response.status;
@ -87,27 +73,6 @@ export default class Startup extends Component<StartupProps, StartupState> {
startupBtnClick = () => { startupBtnClick = () => {
// Startup handle // Startup handle
this.setState(prevState => ({
...prevState,
showStartBtn: false,
statusTxt: "Kapitalismus an die Macht!"
}));
setTimeout(async () => {
try {
let resp = await GameHandler.requestPreparing(this.state.isCloudConnected);
} catch(e)
{
this.setState(prevState => ({
...prevState,
showStartBtn: true,
snackErrorMsg: "Start fehlgeschlagen! \n" + e.toString()
}));
await this.cloudDecision(false);
}
}, 1500)
} }
style = { style = {
@ -123,12 +88,13 @@ export default class Startup extends Component<StartupProps, StartupState> {
}; };
async cloudDecision(decision: boolean) { async cloudDecision(decision: boolean) {
this.setState((prevState) => ({ this.setState((prevState) => ({
...prevState, ...prevState,
openCloudConnectModal: false, openCloudConnectModal: false,
isConnectionIssue: false, isConnectionIssue: false,
isCloudConnected: false, isConnected: false,
startCounter: 30 startCounter: 30
})); }));
clearInterval(this.counterInterval); clearInterval(this.counterInterval);
@ -158,11 +124,12 @@ export default class Startup extends Component<StartupProps, StartupState> {
...prevState, ...prevState,
statusTxt: "Bereit zum Spielen?", statusTxt: "Bereit zum Spielen?",
showStartBtn: true, showStartBtn: true,
isConnectionIssue: !connected,
isConnected: connected
}) })
) )
if(connected) if(connected)
this.counterInterval = setInterval(() => { this.counterInterval = setInterval(() => {
if (!this.props.visible) return;
if(this.state.startCounter == 0) { if(this.state.startCounter == 0) {
clearInterval(this.counterInterval); clearInterval(this.counterInterval);
this.startupBtnClick(); this.startupBtnClick();
@ -184,35 +151,29 @@ export default class Startup extends Component<StartupProps, StartupState> {
startCounter: 30 startCounter: 30
})); }));
this.counterInterval = setInterval(() => { this.counterInterval = setInterval(() => {
if (!this.props.visible) return;
if (this.state.startCounter == 0) {
clearInterval(this.counterInterval);
this.startupBtnClick();
return;
}
this.setState((prevState) => ({ this.setState((prevState) => ({
...prevState, ...prevState,
startCounter: prevState.startCounter-1 startCounter: prevState.startCounter-1
})); }));
if(this.state.startCounter == 0) {
clearInterval(this.counterInterval);
this.startupBtnClick();
}
}, 1000); }, 1000);
} }
} }
render() { render() {
return <div className={`startup ${this.props.visible ? '' : 'hidden'}`}> return <div className="startup">
<Snackbar <Snackbar
open={this.state.snackErrorMsg != ""} open={this.state.cloudErrorMsg != ""}
autoHideDuration={8000} autoHideDuration={8000}
onClose={() => { onClose={() => {this.setState(prevState => ({
this.setState(prevState => ({
...prevState, ...prevState,
snackErrorMsg: "" cloudErrorMsg: ""
})) }))}}
}} message={this.state.cloudErrorMsg}
message={this.state.snackErrorMsg}
/> />
<Dialog <Dialog
open={this.state.isConnectionIssue} open={this.state.isConnectionIssue}
@ -265,8 +226,7 @@ export default class Startup extends Component<StartupProps, StartupState> {
<i>Dafür wird eine WiFi-Verbindung hergestellt</i> <i>Dafür wird eine WiFi-Verbindung hergestellt</i>
<br/> <br/>
<br/> <br/>
<Button variant="contained" sx={{mr: 1}} <Button variant="contained" sx={{mr: 1}} onClick={() => this.cloudDecision(true)}>Ja</Button>
onClick={() => this.cloudDecision(true)}>Ja</Button>
<Button variant="contained" onClick={() => this.cloudDecision(false)} <Button variant="contained" onClick={() => this.cloudDecision(false)}
color="error">Nein</Button> color="error">Nein</Button>
</Typography> </Typography>
@ -283,24 +243,16 @@ export default class Startup extends Component<StartupProps, StartupState> {
<Box alignItems="center" sx={{width: '100%'}}> <Box alignItems="center" sx={{width: '100%'}}>
<FormControl sx={{mr: 2, minWidth: '30%'}}> <FormControl sx={{mr: 2, minWidth: '30%'}}>
<Zoom in={this.state.showStartBtn}><Button color="secondary" {this.state.showStartBtn && <Button color="secondary" variant="contained">Setup <SettingsIcon/></Button>}
onClick={() => window.app.setPage(PAGE.SETUP)}
variant="contained">Einstellungen <SettingsIcon/></Button></Zoom>
</FormControl> </FormControl>
<FormControl sx={{minWidth: '30%'}}> <FormControl sx={{minWidth: '30%'}}>
<Zoom in={this.state.showStartBtn}><Button color="success" {this.state.showStartBtn && <Button color="success" variant="contained">Start <Chip sx={{ml: 1}} size="small" label={this.state.startCounter} /> <PlayCircleIcon/></Button>}
onClick={() => this.startupBtnClick()}
variant="contained">Start <Chip sx={{ml: 1}}
size="small"
label={this.state.startCounter}/>
<PlayCircleIcon/></Button></Zoom>
</FormControl> </FormControl>
</Box> </Box>
<Chip sx={{mt: 3}} color={this.state.isCloudConnected ? "success" : "default"} <Chip sx={{mt: 3}} color={this.state.isConnected ? "success" : "default"} onClick={() => this.setState(prevState => ({
disabled={!this.state.showStartBtn} onClick={() => this.setState(prevState => ({
...prevState, ...prevState,
openCloudConnectModal: true openCloudConnectModal: true
}))} label={this.state.isCloudConnected ? <CloudIcon/> : <CloudOffIcon/>}/> }))} label={this.state.isConnected ? <CloudIcon/> : <CloudOffIcon />}/>
</Stack> </Stack>
</div> </div>

View File

@ -17,7 +17,7 @@ import {
import WifiPasswordIcon from "@mui/icons-material/WifiPassword"; import WifiPasswordIcon from "@mui/icons-material/WifiPassword";
import WifiIcon from "@mui/icons-material/Wifi"; import WifiIcon from "@mui/icons-material/Wifi";
import {IPCAnswer, WiFiNetwork} from "../RawConstants"; import {IPCAnswer, WiFiNetwork} from "../IPCConstants";
interface WiFiState { interface WiFiState {

View File

@ -7,6 +7,3 @@
text-align: center; text-align: center;
} }
.hidden {
display: none;
}

View File

@ -1,13 +1,13 @@
import {IPCAnswer, IPCChannel, IPCListenChannels, IPCRequest} from "../RawConstants"; import {IPCAnswer, IPCChannel, IPCRequest} from "../IPCConstants";
import IpcRendererEvent = Electron.IpcRendererEvent; import IpcRendererEvent = Electron.IpcRendererEvent;
import {App} from "./App"; import {App} from "./App"
export {} export {}
declare global { declare global {
interface Window { interface Window {
"api": { "api": {
request: (channel: IPCChannel, request: IPCRequest, ...args: any) => Promise<IPCAnswer>; request: (channel: IPCChannel, request: IPCRequest, ...args: any) => Promise<IPCAnswer>;
listen: (channel: IPCListenChannels, func: (event: IpcRendererEvent, message: IPCAnswer, ...args: any) => void) => void; listen: (channel: IPCChannel, func: (event: IpcRendererEvent, message: IPCAnswer, ...args: any) => void) => void;
} }
app: App; app: App;
} }

479
yarn.lock

File diff suppressed because it is too large Load Diff