Add electron api context
This commit is contained in:
parent
7e4fee3fe5
commit
4f175a5505
@ -86,6 +86,10 @@ const Entry = () => ({
|
||||
import: source("./Electron/Electron.ts"),
|
||||
dependOn: ["Service"]
|
||||
},
|
||||
|
||||
SimulatorWindow: {
|
||||
import: source("./Electron/SimulatorWindow.ts"),
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -10,6 +10,7 @@ module.exports = (env) => {
|
||||
entry: {
|
||||
Service: AllEntry.Service,
|
||||
Electron: AllEntry.Electron,
|
||||
SimulatorWindow: AllEntry.SimulatorWindow
|
||||
},
|
||||
|
||||
output: Output("[name].js"),
|
||||
|
@ -9,6 +9,7 @@
|
||||
"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",
|
||||
"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",
|
||||
"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",
|
||||
@ -26,6 +27,7 @@
|
||||
"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": "set LIVING_TOGETHER_BASE_PATH=./build& 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",
|
||||
"release-run-electron": "npm run release-desktop-web & npm run copy-fluent-icon & npm run release-electron & npm run electron"
|
||||
},
|
||||
|
@ -35,20 +35,20 @@ div.header-bar {
|
||||
|
||||
div.header-windows-action {
|
||||
height: 100%;
|
||||
width: 135px;
|
||||
min-width: 135px;
|
||||
width: 145px;
|
||||
min-width: 145px;
|
||||
display: flex;
|
||||
|
||||
// 在 Electron 中用于拖拽窗口
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
div.action-button {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: .5em;
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
div.action-button:hover {
|
||||
@ -74,4 +74,21 @@ div.header-bar {
|
||||
background-color: rgba($color: #FFFFFF, $alpha: .1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme";
|
||||
import { LocalizationTooltipHost } from "@Component/Localization/LocalizationTooltipHost";
|
||||
import { useElectron, IMixinElectronProps } from "@Context/Electron";
|
||||
import { I18N } from "@Component/Localization/Localization";
|
||||
import "./HeaderBar.scss";
|
||||
|
||||
@ -78,7 +79,8 @@ class HeaderFpsView extends Component<IMixinStatusProps & IMixinSettingProps, IH
|
||||
}
|
||||
}
|
||||
|
||||
class HeaderWindowsAction extends Component {
|
||||
@useElectron
|
||||
class HeaderWindowsAction extends Component<IMixinElectronProps> {
|
||||
|
||||
public render() {
|
||||
return <Theme className="header-windows-action">
|
||||
@ -88,7 +90,10 @@ class HeaderWindowsAction extends Component {
|
||||
<div className="action-button">
|
||||
<Icon iconName="ChromeRestore"/>
|
||||
</div>
|
||||
<div className="action-button close-button">
|
||||
<div
|
||||
className="action-button close-button"
|
||||
onClick={() => this.props.electron?.close()}
|
||||
>
|
||||
<Icon iconName="ChromeClose"/>
|
||||
</div>
|
||||
</Theme>
|
||||
@ -115,8 +120,13 @@ class HeaderBar extends Component<IHeaderBarProps & IMixinStatusProps & IMixinSe
|
||||
isSaved = status.archive.isSaved;
|
||||
}
|
||||
|
||||
const headerBarClassName = ["header-bar"];
|
||||
if (setting?.platform === Platform.desktop) {
|
||||
headerBarClassName.push("desktop-header-bar");
|
||||
}
|
||||
|
||||
return <Theme
|
||||
className="header-bar"
|
||||
className={headerBarClassName.join(" ")}
|
||||
backgroundLevel={BackgroundLevel.Level1}
|
||||
fontLevel={FontLevel.Level3}
|
||||
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 ((props: any) => {
|
||||
|
||||
|
20
source/Context/Electron.ts
Normal file
20
source/Context/Electron.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { createContext } from "react";
|
||||
import { superConnect } from "@Context/Context";
|
||||
import { ISimulatorAPI } from "@Electron/SimulatorAPI";
|
||||
|
||||
interface IMixinElectronProps {
|
||||
electron?: ISimulatorAPI;
|
||||
}
|
||||
|
||||
const ElectronContext = createContext<ISimulatorAPI>({} as ISimulatorAPI);
|
||||
|
||||
ElectronContext.displayName = "Electron";
|
||||
const ElectronProvider = ElectronContext.Provider;
|
||||
const ElectronConsumer = ElectronContext.Consumer;
|
||||
|
||||
/**
|
||||
* 修饰器
|
||||
*/
|
||||
const useElectron = superConnect<ISimulatorAPI>(ElectronConsumer, "electron");
|
||||
|
||||
export { useElectron, ElectronProvider, IMixinElectronProps, ISimulatorAPI };
|
@ -1,5 +1,6 @@
|
||||
import { app, BrowserWindow } from "electron";
|
||||
import { app, BrowserWindow, ipcMain } from "electron";
|
||||
import { Service } from "@Service/Service";
|
||||
import { join as pathJoin } from "path";
|
||||
const ENV = process.env ?? {};
|
||||
|
||||
class ElectronApp {
|
||||
@ -14,6 +15,11 @@ class ElectronApp {
|
||||
|
||||
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 ?? "");
|
||||
if (isNaN(defaultPort)) defaultPort = undefined;
|
||||
|
||||
@ -22,7 +28,7 @@ class ElectronApp {
|
||||
);
|
||||
}
|
||||
|
||||
public mainWindows?: BrowserWindow;
|
||||
public simulatorWindow?: BrowserWindow;
|
||||
|
||||
public async runMainThread() {
|
||||
|
||||
@ -30,14 +36,36 @@ class ElectronApp {
|
||||
|
||||
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,
|
||||
height: 600,
|
||||
titleBarStyle: 'hidden',
|
||||
frame: false,
|
||||
minWidth: 460,
|
||||
minHeight: 300,
|
||||
webPreferences: { preload }
|
||||
});
|
||||
|
||||
this.mainWindows.loadURL(this.serviceUrl);
|
||||
this.simulatorWindow.loadURL(this.serviceUrl);
|
||||
|
||||
this.handelSimulatorWindowBehavior();
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
}
|
||||
|
||||
private handelSimulatorWindowBehavior() {
|
||||
|
||||
ipcMain.on("close", () => {
|
||||
this.simulatorWindow?.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
25
source/Electron/SimulatorAPI.ts
Normal file
25
source/Electron/SimulatorAPI.ts
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
interface ISimulatorAPI {
|
||||
|
||||
/**
|
||||
* 关闭窗口
|
||||
*/
|
||||
close: () => void;
|
||||
|
||||
/**
|
||||
* 最大化窗口
|
||||
*/
|
||||
maximize: () => void;
|
||||
|
||||
/**
|
||||
* 取消最大化
|
||||
*/
|
||||
unMaximize: () => void;
|
||||
|
||||
/**
|
||||
* 是否处于最大化状态
|
||||
*/
|
||||
isMaximized: () => boolean;
|
||||
}
|
||||
|
||||
export { ISimulatorAPI }
|
19
source/Electron/SimulatorWindow.ts
Normal file
19
source/Electron/SimulatorWindow.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { contextBridge, ipcRenderer } from "electron";
|
||||
import { ISimulatorAPI } from "@Electron/SimulatorAPI"
|
||||
|
||||
const API: ISimulatorAPI = {
|
||||
|
||||
close() {
|
||||
ipcRenderer.send("close");
|
||||
},
|
||||
|
||||
maximize(){},
|
||||
|
||||
unMaximize(){},
|
||||
|
||||
isMaximized(){
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
contextBridge.exposeInMainWorld("API", API);
|
@ -1,7 +1,9 @@
|
||||
import { Component, ReactNode } from "react";
|
||||
import { SettingProvider, Setting, Platform } from "@Context/Setting";
|
||||
import { Theme, BackgroundLevel, FontLevel } from "@Component/Theme/Theme";
|
||||
import { ISimulatorAPI } from "@Electron/SimulatorAPI";
|
||||
import { StatusProvider, Status } from "@Context/Status";
|
||||
import { ElectronProvider } from "@Context/Electron";
|
||||
import { ClassicRenderer } from "@GLRender/ClassicRenderer";
|
||||
import { initializeIcons } from '@fluentui/font-icons-mdl2';
|
||||
import { RootContainer } from "@Component/Container/RootContainer";
|
||||
@ -16,6 +18,11 @@ import "./SimulatorDesktop.scss";
|
||||
initializeIcons("./font-icon/");
|
||||
|
||||
class SimulatorDesktop extends Component {
|
||||
|
||||
/**
|
||||
* Electron API
|
||||
*/
|
||||
public electron: ISimulatorAPI;
|
||||
|
||||
/**
|
||||
* 全局设置
|
||||
@ -47,6 +54,16 @@ class SimulatorDesktop extends Component {
|
||||
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() {
|
||||
@ -82,7 +99,9 @@ class SimulatorDesktop extends Component {
|
||||
public render(): ReactNode {
|
||||
return <SettingProvider value={this.setting}>
|
||||
<StatusProvider value={this.status}>
|
||||
{this.renderContent()}
|
||||
<ElectronProvider value={this.electron}>
|
||||
{this.renderContent()}
|
||||
</ElectronProvider>
|
||||
</StatusProvider>
|
||||
</SettingProvider>
|
||||
}
|
||||
@ -94,9 +113,9 @@ class SimulatorDesktop extends Component {
|
||||
fontLevel={FontLevel.Level3}
|
||||
>
|
||||
<Popup/>
|
||||
<HeaderBar height={45}/>
|
||||
<HeaderBar height={35}/>
|
||||
<div className="app-root-space" style={{
|
||||
height: `calc( 100% - ${45}px)`
|
||||
height: `calc( 100% - ${35}px)`
|
||||
}}>
|
||||
<CommandBar width={45}/>
|
||||
<RootContainer />
|
||||
|
Loading…
Reference in New Issue
Block a user