@netless/window-manager 0.4.9 → 0.4.11-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/AppManager.d.ts +7 -0
- package/dist/AttributesDelegate.d.ts +2 -1
- package/dist/InternalEmitter.d.ts +2 -0
- package/dist/PageState.d.ts +12 -0
- package/dist/Register/index.d.ts +10 -0
- package/dist/callback.d.ts +2 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.es.js +5 -5
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +5 -5
- package/dist/index.umd.js.map +1 -1
- package/docs/advanced.md +24 -0
- package/docs/api.md +9 -0
- package/docs/develop-app.md +60 -22
- package/package.json +2 -2
- package/src/AppContext.ts +12 -3
- package/src/AppManager.ts +90 -37
- package/src/AttributesDelegate.ts +1 -0
- package/src/InternalEmitter.ts +2 -0
- package/src/PageState.ts +31 -0
- package/src/Register/index.ts +28 -1
- package/src/Utils/Common.ts +2 -1
- package/src/callback.ts +2 -0
- package/src/index.ts +24 -0
package/docs/advanced.md
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
- [撤销重做](#redo-undo)
|
5
5
|
- [清屏](#clean-current-scene)
|
6
6
|
- [判断是否打开某种 APP](#has-kind)
|
7
|
+
- [页面控制器](#page-control)
|
7
8
|
|
8
9
|
|
9
10
|
<h3 id="redo-undo">撤销重做</h3>
|
@@ -64,3 +65,26 @@ manager.emitter.on("ready", () => { // ready 事件在所有 app 创建完成后
|
|
64
65
|
const hasSlide = apps.some(app => app.kind === "Slide"); // 判断已经打开的 APP 中是否有 Slide
|
65
66
|
});
|
66
67
|
```
|
68
|
+
|
69
|
+
<br>
|
70
|
+
|
71
|
+
<h3 id="page-control">页面控制器</h3>
|
72
|
+
|
73
|
+
`manager` 提供了一个 `pageState` 来获取当前的 index 和总页数
|
74
|
+
|
75
|
+
```ts
|
76
|
+
manager.pageState.index // 当前的 index
|
77
|
+
manager.pageState.length // 总页数
|
78
|
+
|
79
|
+
manager.emitter.on("pageStateChange", state => {
|
80
|
+
// 当前 index 变化和总页数变化会触发此事件
|
81
|
+
});
|
82
|
+
```
|
83
|
+
|
84
|
+
上一页/下一页/添加一页
|
85
|
+
|
86
|
+
```ts
|
87
|
+
manager.nextPage()
|
88
|
+
manager.prevPage()
|
89
|
+
manager.addPage()
|
90
|
+
```
|
package/docs/api.md
CHANGED
@@ -229,6 +229,7 @@ manager.addPage({ scene: { name: "page2" } }) // 传入 page 信息
|
|
229
229
|
| canRedoSteps | number | | 当前 focus 的 view 可以重做的步数 |
|
230
230
|
| canRedoSteps | number | | 当前 focus 的 view 可以撤销的步数 |
|
231
231
|
| sceneState | SceneState | | 兼容原本 SDK 的 sceneState 属性, 只对 mainView 生效 |
|
232
|
+
| pageState | PageState | | 组合 mainView 的 index 和 scenes 的修改 |
|
232
233
|
|
233
234
|
<br>
|
234
235
|
|
@@ -253,6 +254,7 @@ manager.callbacks.on(events, listener)
|
|
253
254
|
| loadApp | LoadAppEvent | | 加载远程APP 事件 |
|
254
255
|
| ready | undefined | | 当所有 APP 创建完毕时触发 |
|
255
256
|
| sceneStateChange | SceneState | | 当 sceneState 修改时触发 |
|
257
|
+
| pageStateChange | PageState | | |
|
256
258
|
|
257
259
|
```ts
|
258
260
|
type LoadAppEvent = {
|
@@ -260,4 +262,11 @@ type LoadAppEvent = {
|
|
260
262
|
status: "start" | "success" | "failed";
|
261
263
|
reason?: string;
|
262
264
|
}
|
265
|
+
```
|
266
|
+
|
267
|
+
```ts
|
268
|
+
type PageState = {
|
269
|
+
index: number;
|
270
|
+
length: number;
|
271
|
+
}
|
263
272
|
```
|
package/docs/develop-app.md
CHANGED
@@ -11,28 +11,6 @@ const HelloWorld: NetlessApp = {
|
|
11
11
|
kind: "HelloWorld",
|
12
12
|
setup: (context: AppContext) => {
|
13
13
|
context.mountView(context.getBox().$content); // 可选: 挂载 View 到 box 上
|
14
|
-
|
15
|
-
const storage = context.createStorage<{ a: number }>("HelloWorld", { a: 1 });
|
16
|
-
console.log(storage.state === { a: 1 });
|
17
|
-
|
18
|
-
storage.addStateChangedListener(diff => {
|
19
|
-
if (diff.a) {
|
20
|
-
console.log(diff.a.oldValue === 1);
|
21
|
-
console.log(diff.a.newValue === 2);
|
22
|
-
}
|
23
|
-
});
|
24
|
-
|
25
|
-
if (context.getIsWritable()) {
|
26
|
-
// 只有在可写状态才可以调用 setState
|
27
|
-
storage.setState({ a: 2 });
|
28
|
-
}
|
29
|
-
|
30
|
-
// magixEvent 事件是房间内范围的, 建议 app 内使用需要添加自己的 prefix
|
31
|
-
context.addMagixEventListener(`${context.appId}_event1`, message => {
|
32
|
-
console.log("MagixEvent", message);
|
33
|
-
});
|
34
|
-
|
35
|
-
context.dispatchMagixEvent(`${context.appId}_event1`, { count: 1 });
|
36
14
|
},
|
37
15
|
};
|
38
16
|
|
@@ -48,3 +26,63 @@ manager.addApp({
|
|
48
26
|
},
|
49
27
|
});
|
50
28
|
```
|
29
|
+
|
30
|
+
## Counter
|
31
|
+
|
32
|
+
```ts
|
33
|
+
const Counter: NetlessApp<{ count: number }> = {
|
34
|
+
kind: "Counter",
|
35
|
+
setup: (context) => {
|
36
|
+
const storage = context.storage;
|
37
|
+
storage.ensureState({ count: 0 });
|
38
|
+
|
39
|
+
const box = context.getBox(); // box 为这个应用打开的窗口
|
40
|
+
const $content = box.$content // 获取窗口的 content
|
41
|
+
|
42
|
+
const countDom = document.createElement("div");
|
43
|
+
countDom.innerText = storage.state.count.toString();
|
44
|
+
$content.appendChild(countDom);
|
45
|
+
|
46
|
+
// state 变化回调
|
47
|
+
storage.addStateChangedListener(diff => {
|
48
|
+
if (diff.count) {
|
49
|
+
// diff 会给出 newValue 和 oldValue
|
50
|
+
console.log(diff.count.newValue);
|
51
|
+
console.log(diff.count.oldValue);
|
52
|
+
countDom.innerText = diff.count.newValue.toString();
|
53
|
+
}
|
54
|
+
});
|
55
|
+
|
56
|
+
const incButton = document.createElement("button");
|
57
|
+
incButton.innerText = "Inc";
|
58
|
+
const incButtonOnClick = () => {
|
59
|
+
storage.setState({ count: storage.state.count + 1 });
|
60
|
+
}
|
61
|
+
incButton.addEventListener("click", incButtonOnClick);
|
62
|
+
$content.appendChild(incButton);
|
63
|
+
|
64
|
+
const decButton = document.createElement("button");
|
65
|
+
decButton.innerText = "Dec";
|
66
|
+
const decButtonOnClick = () => {
|
67
|
+
storage.setState({ count: storage.state.count - 1 });
|
68
|
+
}
|
69
|
+
decButton.addEventListener("click", decButtonOnClick);
|
70
|
+
$content.appendChild(decButton);
|
71
|
+
|
72
|
+
// 监听事件
|
73
|
+
const event1Disposer = context.addMagixEventListener("event1", msg => {
|
74
|
+
console.log("event1", msg);
|
75
|
+
});
|
76
|
+
|
77
|
+
// 向打开 app 的其他人发送消息
|
78
|
+
context.dispatchMagixEvent("event1", { count: 10 });
|
79
|
+
|
80
|
+
// 应用销毁时, 注意清理掉监听器
|
81
|
+
context.emitter.on("destroy", () => {
|
82
|
+
incButton.removeEventListener("click", incButtonOnClick);
|
83
|
+
decButton.removeEventListener("click", decButtonOnClick);
|
84
|
+
event1Disposer();
|
85
|
+
});
|
86
|
+
}
|
87
|
+
}
|
88
|
+
```
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@netless/window-manager",
|
3
|
-
"version": "0.4.
|
3
|
+
"version": "0.4.11-canary.1",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/index.es.js",
|
6
6
|
"module": "dist/index.es.js",
|
@@ -31,7 +31,7 @@
|
|
31
31
|
"video.js": ">=7"
|
32
32
|
},
|
33
33
|
"devDependencies": {
|
34
|
-
"@netless/app-docs-viewer": "^0.2.
|
34
|
+
"@netless/app-docs-viewer": "^0.2.8",
|
35
35
|
"@netless/app-media-player": "0.1.0-beta.5",
|
36
36
|
"@rollup/plugin-commonjs": "^20.0.0",
|
37
37
|
"@rollup/plugin-node-resolve": "^13.0.4",
|
package/src/AppContext.ts
CHANGED
@@ -165,7 +165,8 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
165
165
|
/** Dispatch events to other clients (and self). */
|
166
166
|
public dispatchMagixEvent: MagixEventDispatcher<TMagixEventPayloads> = (...args) => {
|
167
167
|
// can't dispatch events on replay mode
|
168
|
-
|
168
|
+
const appScopeEvent = `${this.appId}:${args[0]}`;
|
169
|
+
return this.manager.room?.dispatchMagixEvent(appScopeEvent, args[1]);
|
169
170
|
};
|
170
171
|
|
171
172
|
/** Listen to events from others clients (and self messages). */
|
@@ -174,9 +175,17 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
174
175
|
handler,
|
175
176
|
options
|
176
177
|
) => {
|
177
|
-
this.
|
178
|
+
const appScopeEvent = `${this.appId}:${event}`;
|
179
|
+
this.manager.displayer.addMagixEventListener(
|
180
|
+
appScopeEvent,
|
181
|
+
handler as WhiteEventListener,
|
182
|
+
options
|
183
|
+
);
|
178
184
|
return () =>
|
179
|
-
this.manager.displayer.removeMagixEventListener(
|
185
|
+
this.manager.displayer.removeMagixEventListener(
|
186
|
+
appScopeEvent,
|
187
|
+
handler as WhiteEventListener
|
188
|
+
);
|
180
189
|
};
|
181
190
|
|
182
191
|
/** Remove a Magix event listener. */
|
package/src/AppManager.ts
CHANGED
@@ -6,6 +6,7 @@ import { appRegister } from "./Register";
|
|
6
6
|
import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
|
7
7
|
import { callbacks } from "./callback";
|
8
8
|
import { emitter } from "./InternalEmitter";
|
9
|
+
import { Fields, store } from "./AttributesDelegate";
|
9
10
|
import { get, isInteger, orderBy } from "lodash";
|
10
11
|
import { log } from "./Utils/log";
|
11
12
|
import { MainViewProxy } from "./View/MainView";
|
@@ -13,8 +14,8 @@ import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
|
|
13
14
|
import { reconnectRefresher, WindowManager } from "./index";
|
14
15
|
import { RedoUndo } from "./RedoUndo";
|
15
16
|
import { SideEffectManager } from "side-effect-manager";
|
16
|
-
import { store } from "./AttributesDelegate";
|
17
17
|
import { ViewManager } from "./View/ViewManager";
|
18
|
+
import type { SyncRegisterAppPayload } from "./Register";
|
18
19
|
import type { EmitterEvent } from "./InternalEmitter";
|
19
20
|
import {
|
20
21
|
entireScenes,
|
@@ -34,6 +35,7 @@ import type {
|
|
34
35
|
SceneState,
|
35
36
|
} from "white-web-sdk";
|
36
37
|
import type { AddAppParams, BaseInsertParams, TeleBoxRect } from "./index";
|
38
|
+
|
37
39
|
export class AppManager {
|
38
40
|
public displayer: Displayer;
|
39
41
|
public viewManager: ViewManager;
|
@@ -88,33 +90,37 @@ export class AppManager {
|
|
88
90
|
|
89
91
|
emitter.once("onCreated").then(() => this.onCreated());
|
90
92
|
emitter.on("onReconnected", () => this.onReconnected());
|
93
|
+
|
91
94
|
if (isPlayer(this.displayer)) {
|
92
|
-
emitter.on("seek",
|
93
|
-
this.appProxies.forEach(appProxy => {
|
94
|
-
appProxy.onSeek(time);
|
95
|
-
});
|
96
|
-
this.attributesUpdateCallback(this.attributes.apps);
|
97
|
-
this.onAppDelete(this.attributes.apps);
|
98
|
-
});
|
95
|
+
emitter.on("seek", this.onPlayerSeek);
|
99
96
|
}
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
this.onRootDirRemoved();
|
105
|
-
emitter.emit("rootDirRemoved");
|
106
|
-
return;
|
107
|
-
}
|
108
|
-
const mainViewScenePath = this.store.getMainViewScenePath();
|
109
|
-
if (this.room && mainViewScenePath) {
|
110
|
-
if (mainViewScenePath === scenePath) {
|
111
|
-
this.setMainViewScenePath(ROOT_DIR);
|
112
|
-
}
|
113
|
-
}
|
114
|
-
});
|
97
|
+
|
98
|
+
emitter.on("removeScenes", this.onRemoveScenes);
|
99
|
+
emitter.on("setReadonly", this.onReadonlyChanged);
|
100
|
+
|
115
101
|
this.createRootDirScenesCallback();
|
102
|
+
|
103
|
+
appRegister.setSyncRegisterApp(payload => {
|
104
|
+
this.safeUpdateAttributes([Fields.Registered, payload.kind], payload);
|
105
|
+
});
|
116
106
|
}
|
117
107
|
|
108
|
+
private onRemoveScenes = (scenePath: string) => {
|
109
|
+
if (scenePath === ROOT_DIR) {
|
110
|
+
this.setMainViewScenePath("");
|
111
|
+
this.createRootDirScenesCallback();
|
112
|
+
this.onRootDirRemoved();
|
113
|
+
emitter.emit("rootDirRemoved");
|
114
|
+
return;
|
115
|
+
}
|
116
|
+
const mainViewScenePath = this.store.getMainViewScenePath();
|
117
|
+
if (this.room && mainViewScenePath) {
|
118
|
+
if (mainViewScenePath === scenePath) {
|
119
|
+
this.setMainViewScenePath("");
|
120
|
+
}
|
121
|
+
}
|
122
|
+
};
|
123
|
+
|
118
124
|
/**
|
119
125
|
* 根目录被删除时所有的 scene 都会被删除.
|
120
126
|
* 所以需要关掉所有开启了 view 的 app
|
@@ -129,6 +135,20 @@ export class AppManager {
|
|
129
135
|
this.mainViewProxy.rebind();
|
130
136
|
}
|
131
137
|
|
138
|
+
private onReadonlyChanged = () => {
|
139
|
+
this.appProxies.forEach(appProxy => {
|
140
|
+
appProxy.emitAppIsWritableChange();
|
141
|
+
});
|
142
|
+
};
|
143
|
+
|
144
|
+
private onPlayerSeek = (time: number) => {
|
145
|
+
this.appProxies.forEach(appProxy => {
|
146
|
+
appProxy.onSeek(time);
|
147
|
+
});
|
148
|
+
this.attributesUpdateCallback(this.attributes.apps);
|
149
|
+
this.onAppDelete(this.attributes.apps);
|
150
|
+
};
|
151
|
+
|
132
152
|
private createRootDirScenesCallback = () => {
|
133
153
|
let isRecreate = false;
|
134
154
|
if (this.callbacksNode) {
|
@@ -143,7 +163,7 @@ export class AppManager {
|
|
143
163
|
this.updateSceneState(this.callbacksNode);
|
144
164
|
this.mainViewScenesLength = this.callbacksNode.scenes.length;
|
145
165
|
if (isRecreate) {
|
146
|
-
|
166
|
+
this.emitMainViewScenesChange(this.callbacksNode.scenes.length);
|
147
167
|
}
|
148
168
|
}
|
149
169
|
};
|
@@ -151,7 +171,12 @@ export class AppManager {
|
|
151
171
|
private onSceneChange = (node: ScenesCallbacksNode) => {
|
152
172
|
this.mainViewScenesLength = node.scenes.length;
|
153
173
|
this.updateSceneState(node);
|
154
|
-
|
174
|
+
this.emitMainViewScenesChange(this.mainViewScenesLength);
|
175
|
+
};
|
176
|
+
|
177
|
+
private emitMainViewScenesChange = (length: number) => {
|
178
|
+
callbacks.emit("mainViewScenesLengthChange", length);
|
179
|
+
emitter.emit("changePageState");
|
155
180
|
};
|
156
181
|
|
157
182
|
private updateSceneState = (node: ScenesCallbacksNode) => {
|
@@ -236,14 +261,7 @@ export class AppManager {
|
|
236
261
|
this.refresher?.add("minimized", () => {
|
237
262
|
return autorun(() => {
|
238
263
|
const minimized = this.attributes.minimized;
|
239
|
-
|
240
|
-
if (minimized === true) {
|
241
|
-
this.boxManager?.blurAllBox();
|
242
|
-
}
|
243
|
-
setTimeout(() => {
|
244
|
-
this.boxManager?.setMinimized(Boolean(minimized));
|
245
|
-
}, 0);
|
246
|
-
}
|
264
|
+
this.onMinimized(minimized);
|
247
265
|
});
|
248
266
|
});
|
249
267
|
this.refresher?.add("mainViewIndex", () => {
|
@@ -251,6 +269,7 @@ export class AppManager {
|
|
251
269
|
const mainSceneIndex = get(this.attributes, "_mainSceneIndex");
|
252
270
|
if (mainSceneIndex !== undefined && this._prevSceneIndex !== mainSceneIndex) {
|
253
271
|
callbacks.emit("mainViewSceneIndexChange", mainSceneIndex);
|
272
|
+
emitter.emit("changePageState");
|
254
273
|
if (this.callbacksNode) {
|
255
274
|
this.updateSceneState(this.callbacksNode);
|
256
275
|
}
|
@@ -278,13 +297,16 @@ export class AppManager {
|
|
278
297
|
}
|
279
298
|
});
|
280
299
|
});
|
300
|
+
this.refresher?.add("registeredChange", () => {
|
301
|
+
return autorun(() => {
|
302
|
+
const registered = get(this.attributes, Fields.Registered);
|
303
|
+
this.onRegisteredChange(registered);
|
304
|
+
});
|
305
|
+
});
|
281
306
|
if (!this.attributes.apps || Object.keys(this.attributes.apps).length === 0) {
|
282
307
|
const mainScenePath = this.store.getMainViewScenePath();
|
283
308
|
if (!mainScenePath) return;
|
284
|
-
|
285
|
-
if (sceneState.scenePath !== mainScenePath) {
|
286
|
-
setScenePath(this.room, mainScenePath);
|
287
|
-
}
|
309
|
+
this.resetScenePath(mainScenePath);
|
288
310
|
}
|
289
311
|
this.displayerWritableListener(!this.room?.isWritable);
|
290
312
|
this.displayer.callbacks.on("onEnableWriteNowChanged", this.displayerWritableListener);
|
@@ -348,6 +370,30 @@ export class AppManager {
|
|
348
370
|
}
|
349
371
|
}
|
350
372
|
|
373
|
+
private onRegisteredChange = (registered: Record<string, SyncRegisterAppPayload>) => {
|
374
|
+
if (!registered) return;
|
375
|
+
Object.entries(registered).forEach(([kind, payload]) => {
|
376
|
+
if (!appRegister.appClasses.has(kind)) {
|
377
|
+
appRegister.register({
|
378
|
+
kind,
|
379
|
+
src: payload.src,
|
380
|
+
name: payload.name,
|
381
|
+
});
|
382
|
+
}
|
383
|
+
});
|
384
|
+
};
|
385
|
+
|
386
|
+
private onMinimized = (minimized: boolean | undefined) => {
|
387
|
+
if (this.boxManager?.minimized !== minimized) {
|
388
|
+
if (minimized === true) {
|
389
|
+
this.boxManager?.blurAllBox();
|
390
|
+
}
|
391
|
+
setTimeout(() => {
|
392
|
+
this.boxManager?.setMinimized(Boolean(minimized));
|
393
|
+
}, 0);
|
394
|
+
}
|
395
|
+
};
|
396
|
+
|
351
397
|
public refresh() {
|
352
398
|
this.attributesUpdateCallback(this.attributes.apps);
|
353
399
|
}
|
@@ -391,6 +437,13 @@ export class AppManager {
|
|
391
437
|
}
|
392
438
|
}
|
393
439
|
|
440
|
+
private resetScenePath(scenePath: string) {
|
441
|
+
const sceneState = this.displayer.state.sceneState;
|
442
|
+
if (sceneState.scenePath !== scenePath) {
|
443
|
+
setScenePath(this.room, scenePath);
|
444
|
+
}
|
445
|
+
}
|
446
|
+
|
394
447
|
public async addApp(params: AddAppParams, isDynamicPPT: boolean): Promise<string | undefined> {
|
395
448
|
log("addApp", params);
|
396
449
|
const { appId, needFocus } = await this.beforeAddApp(params, isDynamicPPT);
|
package/src/InternalEmitter.ts
CHANGED
@@ -21,6 +21,8 @@ export type EmitterEvent = {
|
|
21
21
|
updateManagerRect: undefined;
|
22
22
|
focusedChange: { focused: string | undefined; prev: string | undefined };
|
23
23
|
rootDirRemoved: undefined;
|
24
|
+
setReadonly: boolean;
|
25
|
+
changePageState: undefined;
|
24
26
|
};
|
25
27
|
|
26
28
|
export type EmitterType = Emittery<EmitterEvent>;
|
package/src/PageState.ts
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
import type { AppManager } from "./AppManager";
|
2
|
+
import { callbacks } from "./callback";
|
3
|
+
import { emitter } from "./InternalEmitter";
|
4
|
+
|
5
|
+
export type PageState = {
|
6
|
+
index: number;
|
7
|
+
length: number;
|
8
|
+
}
|
9
|
+
|
10
|
+
export class PageStateImpl {
|
11
|
+
constructor(private manager: AppManager) {
|
12
|
+
emitter.on("changePageState", () => {
|
13
|
+
callbacks.emit("pageStateChange", this.toObject())
|
14
|
+
});
|
15
|
+
};
|
16
|
+
|
17
|
+
public get index(): number {
|
18
|
+
return this.manager?.store.getMainViewSceneIndex() || 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
public get length(): number {
|
22
|
+
return this.manager?.mainViewScenesLength || 0;
|
23
|
+
}
|
24
|
+
|
25
|
+
public toObject(): PageState {
|
26
|
+
return {
|
27
|
+
index: this.index,
|
28
|
+
length: this.length
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
package/src/Register/index.ts
CHANGED
@@ -8,12 +8,25 @@ export type LoadAppEvent = {
|
|
8
8
|
reason?: string;
|
9
9
|
};
|
10
10
|
|
11
|
+
export type SyncRegisterAppPayload = { kind: string, src: string, name: string | undefined };
|
12
|
+
export type SyncRegisterApp = (payload: SyncRegisterAppPayload) => void;
|
13
|
+
|
11
14
|
class AppRegister {
|
12
15
|
public kindEmitters: Map<string, Emittery<RegisterEvents>> = new Map();
|
13
16
|
public registered: Map<string, RegisterParams> = new Map();
|
14
17
|
public appClassesCache: Map<string, Promise<NetlessApp>> = new Map();
|
15
18
|
public appClasses: Map<string, () => Promise<NetlessApp>> = new Map();
|
16
19
|
|
20
|
+
private syncRegisterApp: SyncRegisterApp | null = null;
|
21
|
+
|
22
|
+
public setSyncRegisterApp(fn: SyncRegisterApp) {
|
23
|
+
this.syncRegisterApp = fn;
|
24
|
+
}
|
25
|
+
|
26
|
+
public onSyncRegisterAppChange = (payload: SyncRegisterAppPayload) => {
|
27
|
+
this.register({ kind: payload.kind, src: payload.src });
|
28
|
+
}
|
29
|
+
|
17
30
|
public async register(params: RegisterParams): Promise<void> {
|
18
31
|
this.appClassesCache.delete(params.kind);
|
19
32
|
this.registered.set(params.kind, params);
|
@@ -23,7 +36,7 @@ class AppRegister {
|
|
23
36
|
|
24
37
|
if (typeof srcOrAppOrFunction === "string") {
|
25
38
|
downloadApp = async () => {
|
26
|
-
let appClass = (await loadApp(srcOrAppOrFunction, params.kind)) as any;
|
39
|
+
let appClass = (await loadApp(srcOrAppOrFunction, params.kind, params.name)) as any;
|
27
40
|
if (appClass) {
|
28
41
|
if (appClass.__esModule) {
|
29
42
|
appClass = appClass.default;
|
@@ -35,6 +48,9 @@ class AppRegister {
|
|
35
48
|
);
|
36
49
|
}
|
37
50
|
};
|
51
|
+
if (this.syncRegisterApp) {
|
52
|
+
this.syncRegisterApp({ kind: params.kind, src: srcOrAppOrFunction, name: params.name });
|
53
|
+
}
|
38
54
|
} else if (typeof srcOrAppOrFunction === "function") {
|
39
55
|
downloadApp = srcOrAppOrFunction;
|
40
56
|
} else {
|
@@ -58,6 +74,17 @@ class AppRegister {
|
|
58
74
|
}
|
59
75
|
}
|
60
76
|
|
77
|
+
public unregister(kind: string) {
|
78
|
+
this.appClasses.delete(kind);
|
79
|
+
this.appClassesCache.delete(kind);
|
80
|
+
this.registered.delete(kind);
|
81
|
+
const kindEmitter = this.kindEmitters.get(kind);
|
82
|
+
if (kindEmitter) {
|
83
|
+
kindEmitter.clearListeners();
|
84
|
+
this.kindEmitters.delete(kind);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
61
88
|
public async notifyApp<T extends keyof RegisterEvents>(
|
62
89
|
kind: string,
|
63
90
|
event: T,
|
package/src/Utils/Common.ts
CHANGED
@@ -33,7 +33,8 @@ export const setViewSceneIndex = (view: View, index: number) => {
|
|
33
33
|
export const setScenePath = (room: Room | undefined, scenePath: string) => {
|
34
34
|
if (room && room.isWritable) {
|
35
35
|
if (room.state.sceneState.scenePath !== scenePath) {
|
36
|
-
|
36
|
+
const nextScenePath = scenePath === "/" ? "" : scenePath;
|
37
|
+
room.setScenePath(nextScenePath);
|
37
38
|
}
|
38
39
|
}
|
39
40
|
};
|
package/src/callback.ts
CHANGED
@@ -2,6 +2,7 @@ import Emittery from "emittery";
|
|
2
2
|
import type { TeleBoxColorScheme, TELE_BOX_STATE } from "@netless/telebox-insider";
|
3
3
|
import type { CameraState, SceneState, ViewVisionMode } from "white-web-sdk";
|
4
4
|
import type { LoadAppEvent } from "./Register";
|
5
|
+
import type { PageState } from "./PageState";
|
5
6
|
|
6
7
|
export type PublicEvent = {
|
7
8
|
mainViewModeChange: ViewVisionMode;
|
@@ -18,6 +19,7 @@ export type PublicEvent = {
|
|
18
19
|
loadApp: LoadAppEvent;
|
19
20
|
ready: undefined; // 所有 APP 创建完毕时触发
|
20
21
|
sceneStateChange: SceneState;
|
22
|
+
pageStateChange: PageState;
|
21
23
|
};
|
22
24
|
|
23
25
|
export type CallbacksType = Emittery<PublicEvent>;
|
package/src/index.ts
CHANGED
@@ -13,6 +13,7 @@ import { initDb } from "./Register/storage";
|
|
13
13
|
import { InvisiblePlugin, isPlayer, isRoom, RoomPhase, ViewMode } from "white-web-sdk";
|
14
14
|
import { isEqual, isNull, isObject, omit } from "lodash";
|
15
15
|
import { log } from "./Utils/log";
|
16
|
+
import { PageStateImpl } from "./PageState";
|
16
17
|
import { ReconnectRefresher } from "./ReconnectRefresher";
|
17
18
|
import { replaceRoomFunction } from "./Utils/RoomHacker";
|
18
19
|
import { setupBuiltin } from "./BuiltinApps";
|
@@ -56,6 +57,7 @@ import type { TeleBoxColorScheme, TeleBoxState } from "@netless/telebox-insider"
|
|
56
57
|
import type { AppProxy } from "./AppProxy";
|
57
58
|
import type { PublicEvent } from "./Callback";
|
58
59
|
import type Emittery from "emittery";
|
60
|
+
import type { PageState } from "./PageState";
|
59
61
|
|
60
62
|
export type WindowMangerAttributes = {
|
61
63
|
modelValue?: string;
|
@@ -168,6 +170,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
|
|
168
170
|
public cursorManager?: CursorManager;
|
169
171
|
public viewMode = ViewMode.Broadcaster;
|
170
172
|
public isReplay = isPlayer(this.displayer);
|
173
|
+
private _pageState?: PageStateImpl;
|
171
174
|
|
172
175
|
private boxManager?: BoxManager;
|
173
176
|
private static params?: MountParams;
|
@@ -235,6 +238,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
|
|
235
238
|
await manager.ensureAttributes();
|
236
239
|
|
237
240
|
manager.appManager = new AppManager(manager);
|
241
|
+
manager._pageState = new PageStateImpl(manager.appManager);
|
238
242
|
manager.cursorManager = new CursorManager(manager.appManager, Boolean(cursor));
|
239
243
|
|
240
244
|
if (params.container) {
|
@@ -368,6 +372,13 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
|
|
368
372
|
return appRegister.register(params);
|
369
373
|
}
|
370
374
|
|
375
|
+
/**
|
376
|
+
* 注销插件
|
377
|
+
*/
|
378
|
+
public static unregister(kind: string) {
|
379
|
+
return appRegister.unregister(kind);
|
380
|
+
}
|
381
|
+
|
371
382
|
/**
|
372
383
|
* 创建一个 app 至白板
|
373
384
|
*/
|
@@ -517,6 +528,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
|
|
517
528
|
public setReadonly(readonly: boolean): void {
|
518
529
|
this.readonly = readonly;
|
519
530
|
this.boxManager?.setReadonly(readonly);
|
531
|
+
emitter.emit("setReadonly", readonly);
|
520
532
|
}
|
521
533
|
|
522
534
|
/**
|
@@ -670,6 +682,14 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
|
|
670
682
|
}
|
671
683
|
}
|
672
684
|
|
685
|
+
public get pageState(): PageState {
|
686
|
+
if (this._pageState) {
|
687
|
+
return this._pageState.toObject();
|
688
|
+
} else {
|
689
|
+
throw new AppManagerNotInitError();
|
690
|
+
}
|
691
|
+
}
|
692
|
+
|
673
693
|
/**
|
674
694
|
* 查询所有的 App
|
675
695
|
*/
|
@@ -855,6 +875,9 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
|
|
855
875
|
if (!this.attributes["_mainSceneIndex"]) {
|
856
876
|
this.safeSetAttributes({ _mainSceneIndex: 0 });
|
857
877
|
}
|
878
|
+
if (!this.attributes[Fields.Registered]) {
|
879
|
+
this.safeSetAttributes({ [Fields.Registered]: {} });
|
880
|
+
}
|
858
881
|
}
|
859
882
|
}
|
860
883
|
}
|
@@ -864,3 +887,4 @@ setupBuiltin();
|
|
864
887
|
export * from "./typings";
|
865
888
|
|
866
889
|
export { BuiltinApps } from "./BuiltinApps";
|
890
|
+
export type { PublicEvent } from "./callback";
|