Merge pull request 'Add auto bundle script' (#41) from dev-mrkbear into master
Reviewed-on: http://git.mrkbear.com/MrKBear/living-together/pulls/41
This commit is contained in:
commit
26837930fe
1
.gitignore
vendored
1
.gitignore
vendored
@ -42,6 +42,7 @@ node_modules/
|
|||||||
jspm_packages/
|
jspm_packages/
|
||||||
build/
|
build/
|
||||||
out/
|
out/
|
||||||
|
bundle/
|
||||||
|
|
||||||
# TypeScript v1 declaration files
|
# TypeScript v1 declaration files
|
||||||
typings/
|
typings/
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 264 KiB |
BIN
assets/living-together.icns
Normal file
BIN
assets/living-together.icns
Normal file
Binary file not shown.
BIN
assets/living-together.ico
Normal file
BIN
assets/living-together.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 MiB |
68
config/electron.forge.config.js
Normal file
68
config/electron.forge.config.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
const FS = require("fs");
|
||||||
|
const Path = require("path");
|
||||||
|
const minimist = require("minimist");
|
||||||
|
|
||||||
|
const args = minimist(process.argv.slice(2));
|
||||||
|
|
||||||
|
const PackageJSON = JSON.parse(
|
||||||
|
FS.readFileSync(Path.join(__dirname, "../package.json"))
|
||||||
|
);
|
||||||
|
|
||||||
|
const Config = {
|
||||||
|
"name": PackageJSON.name,
|
||||||
|
"productName": PackageJSON.name,
|
||||||
|
"version": PackageJSON.version,
|
||||||
|
"description": PackageJSON.description,
|
||||||
|
"main": "./Electron.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "electron-forge start",
|
||||||
|
"package": "electron-forge package",
|
||||||
|
"make": "electron-forge make",
|
||||||
|
"publish": "electron-forge publish",
|
||||||
|
"lint": "echo \"No linting configured\""
|
||||||
|
},
|
||||||
|
"keywords": PackageJSON.keywords,
|
||||||
|
"author": {
|
||||||
|
"name": PackageJSON.author,
|
||||||
|
"email": "mrkbear@qq.com"
|
||||||
|
},
|
||||||
|
"license": PackageJSON.license,
|
||||||
|
"config": {
|
||||||
|
"forge": {
|
||||||
|
"packagerConfig": {
|
||||||
|
"appBundleId": "com.mrkbear.living-together",
|
||||||
|
"appCopyright": "2021-2022 © copyright MrKBear",
|
||||||
|
"download": {
|
||||||
|
"rejectUnauthorized": false,
|
||||||
|
"executableName": "LivingTogether",
|
||||||
|
"mirrorOptions": {
|
||||||
|
"mirror": 'https://npmmirror.com/mirrors/electron/',
|
||||||
|
"customDir": '{{ version }}',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"asar": true,
|
||||||
|
"icon": "./living-together"
|
||||||
|
},
|
||||||
|
"makers": [
|
||||||
|
{
|
||||||
|
"name": "@electron-forge/maker-zip",
|
||||||
|
"platforms": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"electron-squirrel-startup": "^1.0.0",
|
||||||
|
"detect-port": PackageJSON.dependencies["detect-port"],
|
||||||
|
"express": PackageJSON.dependencies["express"],
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@electron-forge/cli": "^6.0.0-beta.63",
|
||||||
|
"@electron-forge/maker-zip": "^6.0.0-beta.63",
|
||||||
|
"electron": PackageJSON.devDependencies.electron
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FS.writeFileSync(Path.join(Path.resolve("./"), args.out ?? "./", "./package.json"), JSON.stringify(Config, null, 4));
|
@ -86,6 +86,10 @@ const Entry = () => ({
|
|||||||
import: source("./Electron/Electron.ts"),
|
import: source("./Electron/Electron.ts"),
|
||||||
dependOn: ["Service"]
|
dependOn: ["Service"]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
SimulatorWindow: {
|
||||||
|
import: source("./Electron/SimulatorWindow.ts"),
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,6 +10,7 @@ module.exports = (env) => {
|
|||||||
entry: {
|
entry: {
|
||||||
Service: AllEntry.Service,
|
Service: AllEntry.Service,
|
||||||
Electron: AllEntry.Electron,
|
Electron: AllEntry.Electron,
|
||||||
|
SimulatorWindow: AllEntry.SimulatorWindow
|
||||||
},
|
},
|
||||||
|
|
||||||
output: Output("[name].js"),
|
output: Output("[name].js"),
|
||||||
@ -24,6 +25,7 @@ module.exports = (env) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// externals: [nodeExternals({ allowlist: [/^(((?!electron).)*)$/] })],
|
||||||
externals: [nodeExternals()],
|
externals: [nodeExternals()],
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
|
13
package.json
13
package.json
@ -9,6 +9,7 @@
|
|||||||
"build-lab": "npm run clean & webpack --mode development --config ./config/webpack.lab.js",
|
"build-lab": "npm run clean & webpack --mode development --config ./config/webpack.lab.js",
|
||||||
"release-lab": "npm run clean & webpack --mode production --no-devtool --config ./config/webpack.lab.js",
|
"release-lab": "npm run clean & webpack --mode production --no-devtool --config ./config/webpack.lab.js",
|
||||||
"hmr-web": "webpack serve --open --config ./config/webpack.web.js",
|
"hmr-web": "webpack serve --open --config ./config/webpack.web.js",
|
||||||
|
"hmr-desktop": "webpack serve --open --config ./config/webpack.desktop.js",
|
||||||
"build-web": "npm run clean & webpack --mode development --config ./config/webpack.web.js",
|
"build-web": "npm run clean & webpack --mode development --config ./config/webpack.web.js",
|
||||||
"release-web": "npm run clean & webpack --mode production --no-devtool --config ./config/webpack.web.js",
|
"release-web": "npm run clean & webpack --mode production --no-devtool --config ./config/webpack.web.js",
|
||||||
"build-desktop-web": "npm run clean & webpack --mode development --config ./config/webpack.desktop.js",
|
"build-desktop-web": "npm run clean & webpack --mode development --config ./config/webpack.desktop.js",
|
||||||
@ -18,16 +19,22 @@
|
|||||||
"run-service": "node ./build/ServiceRunner.js --run --path ./build --port 12000",
|
"run-service": "node ./build/ServiceRunner.js --run --path ./build --port 12000",
|
||||||
"build-run-web": "npm run build-web & npm run build-service & npm run run-service",
|
"build-run-web": "npm run build-web & npm run build-service & npm run run-service",
|
||||||
"release-run-web": "npm run release-web & npm run release-service & npm run run-service",
|
"release-run-web": "npm run release-web & npm run release-service & npm run run-service",
|
||||||
"copy-fluent-icon": "fse mkdirp ./build/font-icon/ && fse emptyDir ./build/font-icon/ && fse copy ./node_modules/@fluentui/font-icons-mdl2/fonts/ ./build/font-icon/",
|
"copy-fluent-icon": "fse mkdirp ./build/font-icon/ & fse emptyDir ./build/font-icon/ & fse copy ./node_modules/@fluentui/font-icons-mdl2/fonts/ ./build/font-icon/",
|
||||||
"build-run-desktop-web": "npm run build-desktop-web & npm run copy-fluent-icon & npm run build-service & npm run run-service",
|
"build-run-desktop-web": "npm run build-desktop-web & npm run copy-fluent-icon & npm run build-service & npm run run-service",
|
||||||
"release-run-desktop-web": "npm run release-desktop-web & npm run copy-fluent-icon & npm run release-service & npm run run-service",
|
"release-run-desktop-web": "npm run release-desktop-web & npm run copy-fluent-icon & npm run release-service & npm run run-service",
|
||||||
"skip-electron-ci": "set ELECTRON_SKIP_BINARY_DOWNLOAD=1& npm ci",
|
"skip-electron-ci": "set ELECTRON_SKIP_BINARY_DOWNLOAD=1& npm ci",
|
||||||
"build-electron": "webpack --mode development --config ./config/webpack.electron.js",
|
"build-electron": "webpack --mode development --config ./config/webpack.electron.js",
|
||||||
"release-electron": "webpack --mode production --no-devtool --config ./config/webpack.electron.js",
|
"release-electron": "webpack --mode production --no-devtool --config ./config/webpack.electron.js",
|
||||||
"electron-cache": "set ELECTRON_SKIP_BINARY_DOWNLOAD=& set ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/& set ELECTRON_CUSTOM_DIR={{ version }}& node ./node_modules/electron/install.js",
|
"electron-cache": "set ELECTRON_SKIP_BINARY_DOWNLOAD=& set ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/& set ELECTRON_CUSTOM_DIR={{ version }}& node ./node_modules/electron/install.js",
|
||||||
"electron": "set LIVING_TOGETHER_BASE_PATH=./build& npx electron ./build/Electron.js",
|
"electron": "set LIVING_TOGETHER_BASE_PATH=./build& set LIVING_TOGETHER_WEB_PATH=/& npx electron ./build/Electron.js",
|
||||||
|
"hmr-electron": "npm run build-electron & set LIVING_TOGETHER_SERVICE=http://127.0.0.1:12000& npm run electron",
|
||||||
"build-run-electron": "npm run build-desktop-web & npm run copy-fluent-icon & npm run build-electron & npm run electron",
|
"build-run-electron": "npm run build-desktop-web & npm run copy-fluent-icon & npm run build-electron & npm run electron",
|
||||||
"release-run-electron": "npm run release-desktop-web & npm run copy-fluent-icon & npm run release-electron & npm run electron"
|
"release-run-electron": "npm run release-desktop-web & npm run copy-fluent-icon & npm run release-electron & npm run electron",
|
||||||
|
"copy-package-json": "fse mkdirp ./bundle/ & node ./config/electron.forge.config.js --out ./bundle",
|
||||||
|
"copy-build-result": "fse mkdirp ./bundle/ & fse mkdirp ./build/ & fse copy ./build/ ./bundle/",
|
||||||
|
"copy-electron-icon": "fse mkdirp ./bundle/ & fse copy ./assets/living-together.ico ./bundle/living-together.ico & fse copy ./assets/living-together.icns ./bundle/living-together.icns",
|
||||||
|
"electron-app-ci": "cd ./bundle & npm install & cd ../",
|
||||||
|
"gen-bundle": "fse emptyDir ./bundle/ & npm run copy-package-json & npm run copy-electron-icon & npm run electron-app-ci"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"artwork",
|
"artwork",
|
||||||
|
@ -35,20 +35,20 @@ div.header-bar {
|
|||||||
|
|
||||||
div.header-windows-action {
|
div.header-windows-action {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 135px;
|
width: 145px;
|
||||||
min-width: 135px;
|
min-width: 145px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
// 在 Electron 中用于拖拽窗口
|
// 在 Electron 中用于拖拽窗口
|
||||||
-webkit-app-region: no-drag;
|
-webkit-app-region: no-drag;
|
||||||
|
|
||||||
div.action-button {
|
div.action-button {
|
||||||
width: 45px;
|
width: 100%;
|
||||||
height: 45px;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-size: .5em;
|
font-size: .8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.action-button:hover {
|
div.action-button:hover {
|
||||||
@ -75,3 +75,20 @@ div.header-bar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.header-bar.desktop-header-bar {
|
||||||
|
font-size: .9em;
|
||||||
|
|
||||||
|
div.title > i, div.fps-view > i {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.title > span {
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.title {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import { useStatusWithEvent, useStatus, IMixinStatusProps } from "@Context/Statu
|
|||||||
import { useSettingWithEvent, IMixinSettingProps, Platform } from "@Context/Setting";
|
import { useSettingWithEvent, IMixinSettingProps, Platform } from "@Context/Setting";
|
||||||
import { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme";
|
import { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme";
|
||||||
import { LocalizationTooltipHost } from "@Component/Localization/LocalizationTooltipHost";
|
import { LocalizationTooltipHost } from "@Component/Localization/LocalizationTooltipHost";
|
||||||
|
import { useElectronWithEvent, IMixinElectronProps } from "@Context/Electron";
|
||||||
import { I18N } from "@Component/Localization/Localization";
|
import { I18N } from "@Component/Localization/Localization";
|
||||||
import "./HeaderBar.scss";
|
import "./HeaderBar.scss";
|
||||||
|
|
||||||
@ -78,18 +79,41 @@ class HeaderFpsView extends Component<IMixinStatusProps & IMixinSettingProps, IH
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HeaderWindowsAction extends Component {
|
@useElectronWithEvent("windowsSizeStateChange")
|
||||||
|
class HeaderWindowsAction extends Component<IMixinElectronProps> {
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
||||||
|
const isMaxSize = this.props.electron?.isMaximized();
|
||||||
|
|
||||||
return <Theme className="header-windows-action">
|
return <Theme className="header-windows-action">
|
||||||
<div className="action-button">
|
<div
|
||||||
<Icon iconName="ChromeMinimize"/>
|
className="action-button"
|
||||||
|
onClick={() => {
|
||||||
|
this.props.electron?.minimize();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon iconName="Remove"/>
|
||||||
</div>
|
</div>
|
||||||
<div className="action-button">
|
<div
|
||||||
<Icon iconName="ChromeRestore"/>
|
className="action-button"
|
||||||
|
onClick={() => {
|
||||||
|
if (isMaxSize) {
|
||||||
|
this.props.electron?.unMaximize();
|
||||||
|
} else {
|
||||||
|
this.props.electron?.maximize();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon iconName={ isMaxSize ? "ArrangeSendBackward" : "Checkbox"}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="action-button close-button">
|
<div
|
||||||
<Icon iconName="ChromeClose"/>
|
className="action-button close-button"
|
||||||
|
onClick={() => {
|
||||||
|
this.props.electron?.close()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon iconName="Clear"/>
|
||||||
</div>
|
</div>
|
||||||
</Theme>
|
</Theme>
|
||||||
}
|
}
|
||||||
@ -115,8 +139,13 @@ class HeaderBar extends Component<IHeaderBarProps & IMixinStatusProps & IMixinSe
|
|||||||
isSaved = status.archive.isSaved;
|
isSaved = status.archive.isSaved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const headerBarClassName = ["header-bar"];
|
||||||
|
if (setting?.platform === Platform.desktop) {
|
||||||
|
headerBarClassName.push("desktop-header-bar");
|
||||||
|
}
|
||||||
|
|
||||||
return <Theme
|
return <Theme
|
||||||
className="header-bar"
|
className={headerBarClassName.join(" ")}
|
||||||
backgroundLevel={BackgroundLevel.Level1}
|
backgroundLevel={BackgroundLevel.Level1}
|
||||||
fontLevel={FontLevel.Level3}
|
fontLevel={FontLevel.Level3}
|
||||||
style={{ height: this.props.height }}
|
style={{ height: this.props.height }}
|
||||||
|
@ -58,7 +58,7 @@ function superConnectWithEvent<C extends Emitter<E>, E extends Record<EventType,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function superConnect<C extends Emitter<any>>(consumer: Consumer<C>, keyName: string) {
|
function superConnect<C>(consumer: Consumer<C>, keyName: string) {
|
||||||
return <R extends RenderComponent>(components: R): R => {
|
return <R extends RenderComponent>(components: R): R => {
|
||||||
return ((props: any) => {
|
return ((props: any) => {
|
||||||
|
|
||||||
|
22
source/Context/Electron.ts
Normal file
22
source/Context/Electron.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { createContext } from "react";
|
||||||
|
import { superConnect, superConnectWithEvent } from "@Context/Context";
|
||||||
|
import { ISimulatorAPI, IApiEmitterEvent } from "@Electron/SimulatorAPI";
|
||||||
|
|
||||||
|
interface IMixinElectronProps {
|
||||||
|
electron?: ISimulatorAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ElectronContext = createContext<ISimulatorAPI>((window as any).API ?? {} as ISimulatorAPI);
|
||||||
|
|
||||||
|
ElectronContext.displayName = "Electron";
|
||||||
|
const ElectronProvider = ElectronContext.Provider;
|
||||||
|
const ElectronConsumer = ElectronContext.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修饰器
|
||||||
|
*/
|
||||||
|
const useElectron = superConnect<ISimulatorAPI>(ElectronConsumer, "electron");
|
||||||
|
|
||||||
|
const useElectronWithEvent = superConnectWithEvent<ISimulatorAPI, IApiEmitterEvent>(ElectronConsumer, "electron");
|
||||||
|
|
||||||
|
export { useElectron, ElectronProvider, IMixinElectronProps, ISimulatorAPI, useElectronWithEvent };
|
@ -1,5 +1,6 @@
|
|||||||
import { app, BrowserWindow } from "electron";
|
import { app, BrowserWindow, ipcMain } from "electron";
|
||||||
import { Service } from "@Service/Service";
|
import { Service } from "@Service/Service";
|
||||||
|
import { join as pathJoin } from "path";
|
||||||
const ENV = process.env ?? {};
|
const ENV = process.env ?? {};
|
||||||
|
|
||||||
class ElectronApp {
|
class ElectronApp {
|
||||||
@ -14,6 +15,11 @@ class ElectronApp {
|
|||||||
|
|
||||||
public async runService() {
|
public async runService() {
|
||||||
|
|
||||||
|
if (ENV.LIVING_TOGETHER_SERVICE) {
|
||||||
|
this.serviceUrl = ENV.LIVING_TOGETHER_SERVICE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let defaultPort: number | undefined = parseInt(ENV.LIVING_TOGETHER_DEFAULT_PORT ?? "");
|
let defaultPort: number | undefined = parseInt(ENV.LIVING_TOGETHER_DEFAULT_PORT ?? "");
|
||||||
if (isNaN(defaultPort)) defaultPort = undefined;
|
if (isNaN(defaultPort)) defaultPort = undefined;
|
||||||
|
|
||||||
@ -22,7 +28,7 @@ class ElectronApp {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public mainWindows?: BrowserWindow;
|
public simulatorWindow?: BrowserWindow;
|
||||||
|
|
||||||
public async runMainThread() {
|
public async runMainThread() {
|
||||||
|
|
||||||
@ -30,14 +36,59 @@ class ElectronApp {
|
|||||||
|
|
||||||
await this.runService();
|
await this.runService();
|
||||||
|
|
||||||
this.mainWindows = new BrowserWindow({
|
let preload = pathJoin(__dirname, "./SimulatorWindow.js");
|
||||||
|
|
||||||
|
// if (ENV.LIVING_TOGETHER_BASE_PATH) {
|
||||||
|
// preload = pathJoin(__dirname, ENV.LIVING_TOGETHER_BASE_PATH, "./SimulatorWindow.js");
|
||||||
|
// }
|
||||||
|
|
||||||
|
this.simulatorWindow = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
titleBarStyle: 'hidden',
|
titleBarStyle: 'hidden',
|
||||||
frame: false,
|
frame: false,
|
||||||
|
minWidth: 460,
|
||||||
|
minHeight: 300,
|
||||||
|
webPreferences: { preload }
|
||||||
});
|
});
|
||||||
|
|
||||||
this.mainWindows.loadURL(this.serviceUrl);
|
this.simulatorWindow.loadURL(this.serviceUrl + (ENV.LIVING_TOGETHER_WEB_PATH ?? "/resources/app.asar/"));
|
||||||
|
|
||||||
|
this.handelSimulatorWindowBehavior();
|
||||||
|
|
||||||
|
app.on('window-all-closed', function () {
|
||||||
|
if (process.platform !== 'darwin') app.quit()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private handelSimulatorWindowBehavior() {
|
||||||
|
|
||||||
|
ipcMain.on("windows.close", () => {
|
||||||
|
this.simulatorWindow?.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on("windows.maximize", () => {
|
||||||
|
this.simulatorWindow?.maximize();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on("windows.unMaximize", () => {
|
||||||
|
this.simulatorWindow?.unmaximize();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on("windows.isMaximized", (event) => {
|
||||||
|
event.returnValue = this.simulatorWindow?.isMaximized();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on("windows.minimize", (event) => {
|
||||||
|
this.simulatorWindow?.minimize();
|
||||||
|
});
|
||||||
|
|
||||||
|
const sendWindowsChangeMessage = () => {
|
||||||
|
this.simulatorWindow?.webContents.send("windows.windowsSizeStateChange");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.simulatorWindow?.on("maximize", sendWindowsChangeMessage);
|
||||||
|
this.simulatorWindow?.on("unmaximize", sendWindowsChangeMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
source/Electron/SimulatorAPI.ts
Normal file
35
source/Electron/SimulatorAPI.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { Emitter } from "@Model/Emitter";
|
||||||
|
|
||||||
|
type IApiEmitterEvent = {
|
||||||
|
windowsSizeStateChange: void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISimulatorAPI extends Emitter<IApiEmitterEvent> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭窗口
|
||||||
|
*/
|
||||||
|
close: () => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大化窗口
|
||||||
|
*/
|
||||||
|
maximize: () => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消最大化
|
||||||
|
*/
|
||||||
|
unMaximize: () => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否处于最大化状态
|
||||||
|
*/
|
||||||
|
isMaximized: () => boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否处于最大化状态
|
||||||
|
*/
|
||||||
|
minimize: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ISimulatorAPI, IApiEmitterEvent }
|
64
source/Electron/SimulatorWindow.ts
Normal file
64
source/Electron/SimulatorWindow.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { contextBridge, ipcRenderer } from "electron";
|
||||||
|
import { ISimulatorAPI } from "@Electron/SimulatorAPI"
|
||||||
|
|
||||||
|
const emitterMap: Array<[key: string, value: Function[]]> = [];
|
||||||
|
const queryEmitter = (key: string) => {
|
||||||
|
let res: (typeof emitterMap)[0] | undefined;
|
||||||
|
emitterMap.forEach((item) => {
|
||||||
|
if (item[0] === key) res = item;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
if (Array.isArray(res[1])) return res[1];
|
||||||
|
res[1] = [];
|
||||||
|
return res[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
res = [key, []];
|
||||||
|
emitterMap.push(res);
|
||||||
|
return res[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const API: ISimulatorAPI = {
|
||||||
|
|
||||||
|
close() {
|
||||||
|
ipcRenderer.send("windows.close");
|
||||||
|
},
|
||||||
|
|
||||||
|
maximize() {
|
||||||
|
ipcRenderer.send("windows.maximize");
|
||||||
|
},
|
||||||
|
|
||||||
|
unMaximize() {
|
||||||
|
ipcRenderer.send("windows.unMaximize");
|
||||||
|
},
|
||||||
|
|
||||||
|
isMaximized() {
|
||||||
|
return ipcRenderer.sendSync("windows.isMaximized");
|
||||||
|
},
|
||||||
|
|
||||||
|
minimize() {
|
||||||
|
ipcRenderer.send("windows.minimize");
|
||||||
|
},
|
||||||
|
|
||||||
|
all: new Map() as any,
|
||||||
|
|
||||||
|
resetAll: () => emitterMap.splice(0),
|
||||||
|
reset: (type) => queryEmitter(type).splice(0),
|
||||||
|
on: (type, handler) => queryEmitter(type).push(handler),
|
||||||
|
off: (type, handler) => {
|
||||||
|
const handlers = queryEmitter(type);
|
||||||
|
handlers.splice(handlers.indexOf(handler!) >>> 0, 1);
|
||||||
|
},
|
||||||
|
emit: ((type: string, evt: any) => {
|
||||||
|
queryEmitter(type).slice().map((handler: any) => { handler(evt) });
|
||||||
|
}) as any,
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcRenderer.on("windows.windowsSizeStateChange", () => {
|
||||||
|
API.emit("windowsSizeStateChange");
|
||||||
|
});
|
||||||
|
|
||||||
|
contextBridge.exposeInMainWorld("API", API);
|
@ -1,7 +1,9 @@
|
|||||||
import { Component, ReactNode } from "react";
|
import { Component, ReactNode } from "react";
|
||||||
import { SettingProvider, Setting, Platform } from "@Context/Setting";
|
import { SettingProvider, Setting, Platform } from "@Context/Setting";
|
||||||
import { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme";
|
import { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme";
|
||||||
|
import { ISimulatorAPI } from "@Electron/SimulatorAPI";
|
||||||
import { StatusProvider, Status } from "@Context/Status";
|
import { StatusProvider, Status } from "@Context/Status";
|
||||||
|
import { ElectronProvider } from "@Context/Electron";
|
||||||
import { ClassicRenderer } from "@GLRender/ClassicRenderer";
|
import { ClassicRenderer } from "@GLRender/ClassicRenderer";
|
||||||
import { initializeIcons } from '@fluentui/font-icons-mdl2';
|
import { initializeIcons } from '@fluentui/font-icons-mdl2';
|
||||||
import { RootContainer } from "@Component/Container/RootContainer";
|
import { RootContainer } from "@Component/Container/RootContainer";
|
||||||
@ -17,6 +19,11 @@ initializeIcons("./font-icon/");
|
|||||||
|
|
||||||
class SimulatorDesktop extends Component {
|
class SimulatorDesktop extends Component {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Electron API
|
||||||
|
*/
|
||||||
|
public electron: ISimulatorAPI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局设置
|
* 全局设置
|
||||||
*/
|
*/
|
||||||
@ -47,6 +54,16 @@ class SimulatorDesktop extends Component {
|
|||||||
individual.position[2] = (Math.random() - .5) * 2;
|
individual.position[2] = (Math.random() - .5) * 2;
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(window as any).setting = this.setting;
|
||||||
|
(window as any).status = this.status;
|
||||||
|
|
||||||
|
this.electron = {} as ISimulatorAPI;
|
||||||
|
if ((window as any).API) {
|
||||||
|
this.electron = (window as any).API;
|
||||||
|
} else {
|
||||||
|
console.error("SimulatorDesktop: Can't find electron API");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
@ -82,7 +99,9 @@ class SimulatorDesktop extends Component {
|
|||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
return <SettingProvider value={this.setting}>
|
return <SettingProvider value={this.setting}>
|
||||||
<StatusProvider value={this.status}>
|
<StatusProvider value={this.status}>
|
||||||
{this.renderContent()}
|
<ElectronProvider value={this.electron}>
|
||||||
|
{this.renderContent()}
|
||||||
|
</ElectronProvider>
|
||||||
</StatusProvider>
|
</StatusProvider>
|
||||||
</SettingProvider>
|
</SettingProvider>
|
||||||
}
|
}
|
||||||
@ -94,9 +113,9 @@ class SimulatorDesktop extends Component {
|
|||||||
fontLevel={FontLevel.Level3}
|
fontLevel={FontLevel.Level3}
|
||||||
>
|
>
|
||||||
<Popup/>
|
<Popup/>
|
||||||
<HeaderBar height={45}/>
|
<HeaderBar height={35}/>
|
||||||
<div className="app-root-space" style={{
|
<div className="app-root-space" style={{
|
||||||
height: `calc( 100% - ${45}px)`
|
height: `calc( 100% - ${35}px)`
|
||||||
}}>
|
}}>
|
||||||
<CommandBar width={45}/>
|
<CommandBar width={45}/>
|
||||||
<RootContainer />
|
<RootContainer />
|
||||||
|
@ -42,7 +42,7 @@ class Service {
|
|||||||
|
|
||||||
console.log("Service: service run in port " + this.servicePort);
|
console.log("Service: service run in port " + this.servicePort);
|
||||||
|
|
||||||
return "http://127.0.0.1:" + this.servicePort + "/";
|
return "http://127.0.0.1:" + this.servicePort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user