@netless/window-manager 0.4.12 → 0.4.15
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 +12 -0
- package/README.md +1 -0
- package/dist/AppListener.d.ts +1 -0
- package/dist/AppManager.d.ts +4 -2
- package/dist/ScenePath/index.d.ts +12 -0
- package/dist/constants.d.ts +2 -1
- 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 +14 -1
- package/docs/app-context.md +111 -0
- package/docs/develop-app.md +2 -0
- package/package.json +1 -1
- package/src/AppListener.ts +8 -0
- package/src/AppManager.ts +39 -28
- package/src/ScenePath/index.ts +47 -0
- package/src/View/MainView.ts +2 -1
- package/src/constants.ts +1 -0
- package/src/index.ts +3 -2
package/docs/advanced.md
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
- [清屏](#clean-current-scene)
|
6
6
|
- [判断是否打开某种 APP](#has-kind)
|
7
7
|
- [页面控制器](#page-control)
|
8
|
+
- [视角](#view-mode)
|
8
9
|
|
9
10
|
|
10
11
|
<h3 id="redo-undo">撤销重做</h3>
|
@@ -87,4 +88,16 @@ manager.emitter.on("pageStateChange", state => {
|
|
87
88
|
manager.nextPage()
|
88
89
|
manager.prevPage()
|
89
90
|
manager.addPage()
|
90
|
-
```
|
91
|
+
```
|
92
|
+
|
93
|
+
<br>
|
94
|
+
|
95
|
+
<h3 id="view-mode">视角跟随</h3>
|
96
|
+
|
97
|
+
`ViewMode` 有 `broadcaster` `freedom` 两种模式
|
98
|
+
|
99
|
+
可写权限默认进去为 `broadcaster` 并且互相操作并跟随视角
|
100
|
+
|
101
|
+
当 `room` 设置 `Writable` 为 `false` 时此时只能跟随视角并不能广播视角
|
102
|
+
|
103
|
+
在 `room` 的 `isWritable` 设置为 `false` 后想重新跟随视角可以通过设置为 `broadcaster` 跟随
|
@@ -0,0 +1,111 @@
|
|
1
|
+
## AppContext
|
2
|
+
|
3
|
+
- [api](#api)
|
4
|
+
- [events](#events)
|
5
|
+
|
6
|
+
<h2 id="api">API</h2>
|
7
|
+
|
8
|
+
### appId
|
9
|
+
|
10
|
+
插入 `app` 时生成的唯一 ID
|
11
|
+
|
12
|
+
```ts
|
13
|
+
const appId = context.appId
|
14
|
+
```
|
15
|
+
|
16
|
+
### getDisplayer
|
17
|
+
|
18
|
+
在默认情况下 `Displayer` 为白板的 `room` 实例
|
19
|
+
|
20
|
+
回放时则为 `Player` 实例
|
21
|
+
|
22
|
+
```ts
|
23
|
+
const displayer = context.getDisplayer()
|
24
|
+
|
25
|
+
assert(displayer, room) // 互动房间
|
26
|
+
assert(displayer, player) // 回放房间
|
27
|
+
```
|
28
|
+
|
29
|
+
### getScenes
|
30
|
+
|
31
|
+
`scenes` 在 `addApp` 时传入 `scenePath` 会由 `WindowManager` 创建
|
32
|
+
|
33
|
+
```ts
|
34
|
+
const scenes = context.getScenes()
|
35
|
+
```
|
36
|
+
|
37
|
+
### getView
|
38
|
+
|
39
|
+
`View` 为白板中一块可标注部分
|
40
|
+
|
41
|
+
```ts
|
42
|
+
const view = context.getView()
|
43
|
+
```
|
44
|
+
|
45
|
+
### getIsWritable
|
46
|
+
|
47
|
+
获取当前状态是否可写
|
48
|
+
|
49
|
+
```ts
|
50
|
+
// isWritable === (room.isWritable && box.readonly)
|
51
|
+
const isWritable = context.getIsWritable()
|
52
|
+
```
|
53
|
+
|
54
|
+
### getBox
|
55
|
+
|
56
|
+
获取当前 app 的 box
|
57
|
+
|
58
|
+
```ts
|
59
|
+
const box = context.getBox()
|
60
|
+
|
61
|
+
box.$content // box 的 main element
|
62
|
+
box.$footer
|
63
|
+
```
|
64
|
+
|
65
|
+
### setScenePath
|
66
|
+
|
67
|
+
切换当前 `view` 的 `scenePath`
|
68
|
+
|
69
|
+
```ts
|
70
|
+
context.setScenePath("/page/2")
|
71
|
+
```
|
72
|
+
|
73
|
+
### mountView
|
74
|
+
|
75
|
+
挂载 view 到指定 dom
|
76
|
+
|
77
|
+
```ts
|
78
|
+
context.mountView(ref)
|
79
|
+
```
|
80
|
+
|
81
|
+
<h2 id="events">events</h2>
|
82
|
+
|
83
|
+
### destroy
|
84
|
+
|
85
|
+
app 被关闭时发送的事件
|
86
|
+
|
87
|
+
```ts
|
88
|
+
context.emitter.on("destroy", () => {
|
89
|
+
// release your listeners
|
90
|
+
})
|
91
|
+
```
|
92
|
+
|
93
|
+
### writableChange
|
94
|
+
|
95
|
+
白板可写状态切换时触发
|
96
|
+
|
97
|
+
```ts
|
98
|
+
context.emitter.on("writableChange", isWritable => {
|
99
|
+
//
|
100
|
+
})
|
101
|
+
```
|
102
|
+
|
103
|
+
### focus
|
104
|
+
|
105
|
+
当前 app 获得焦点或者失去焦点时触发
|
106
|
+
|
107
|
+
```ts
|
108
|
+
context.emitter.on("focus", focus => {
|
109
|
+
//
|
110
|
+
})
|
111
|
+
```
|
package/docs/develop-app.md
CHANGED
package/package.json
CHANGED
package/src/AppListener.ts
CHANGED
@@ -55,6 +55,10 @@ export class AppListeners {
|
|
55
55
|
this.cursorMoveHandler(data.payload);
|
56
56
|
break;
|
57
57
|
}
|
58
|
+
case Events.RootDirRemoved: {
|
59
|
+
this.rootDirRemovedHandler();
|
60
|
+
break;
|
61
|
+
}
|
58
62
|
default:
|
59
63
|
break;
|
60
64
|
}
|
@@ -93,4 +97,8 @@ export class AppListeners {
|
|
93
97
|
private cursorMoveHandler = (payload: any) => {
|
94
98
|
emitter.emit("cursorMove", payload);
|
95
99
|
};
|
100
|
+
|
101
|
+
private rootDirRemovedHandler = () => {
|
102
|
+
this.manager.onRootDirRemoved();
|
103
|
+
};
|
96
104
|
}
|
package/src/AppManager.ts
CHANGED
@@ -109,10 +109,8 @@ export class AppManager {
|
|
109
109
|
private onRemoveScenes = (scenePath: string) => {
|
110
110
|
// 如果移除根目录就把 scenePath 设置为初始值
|
111
111
|
if (scenePath === ROOT_DIR) {
|
112
|
-
this.setMainViewScenePath(INIT_DIR);
|
113
|
-
this.createRootDirScenesCallback();
|
114
112
|
this.onRootDirRemoved();
|
115
|
-
|
113
|
+
this.dispatchInternalEvent(Events.RootDirRemoved);
|
116
114
|
return;
|
117
115
|
}
|
118
116
|
// 如果移除的 path 跟 MainViewScenePath 相同就取当前目录的当前 index
|
@@ -129,7 +127,10 @@ export class AppManager {
|
|
129
127
|
* 根目录被删除时所有的 scene 都会被删除.
|
130
128
|
* 所以需要关掉所有开启了 view 的 app
|
131
129
|
*/
|
132
|
-
|
130
|
+
public onRootDirRemoved() {
|
131
|
+
this.setMainViewScenePath(INIT_DIR);
|
132
|
+
this.createRootDirScenesCallback();
|
133
|
+
|
133
134
|
this.appProxies.forEach(appProxy => {
|
134
135
|
if (appProxy.view) {
|
135
136
|
this.closeApp(appProxy.id);
|
@@ -137,6 +138,8 @@ export class AppManager {
|
|
137
138
|
});
|
138
139
|
// 删除了根目录的 scenes 之后 mainview 需要重新绑定, 否则主白板会不能渲染
|
139
140
|
this.mainViewProxy.rebind();
|
141
|
+
|
142
|
+
emitter.emit("rootDirRemoved");
|
140
143
|
}
|
141
144
|
|
142
145
|
private onReadonlyChanged = () => {
|
@@ -274,34 +277,13 @@ export class AppManager {
|
|
274
277
|
this.refresher?.add("mainViewIndex", () => {
|
275
278
|
return autorun(() => {
|
276
279
|
const mainSceneIndex = get(this.attributes, "_mainSceneIndex");
|
277
|
-
|
278
|
-
callbacks.emit("mainViewSceneIndexChange", mainSceneIndex);
|
279
|
-
emitter.emit("changePageState");
|
280
|
-
if (this.callbacksNode) {
|
281
|
-
this.updateSceneState(this.callbacksNode);
|
282
|
-
}
|
283
|
-
this._prevSceneIndex = mainSceneIndex;
|
284
|
-
}
|
280
|
+
this.onMainViewIndexChange(mainSceneIndex);
|
285
281
|
});
|
286
282
|
});
|
287
283
|
this.refresher?.add("focusedChange", () => {
|
288
284
|
return autorun(() => {
|
289
285
|
const focused = get(this.attributes, "focus");
|
290
|
-
|
291
|
-
callbacks.emit("focusedChange", focused);
|
292
|
-
emitter.emit("focusedChange", { focused, prev: this._prevFocused });
|
293
|
-
this._prevFocused = focused;
|
294
|
-
if (focused !== undefined) {
|
295
|
-
this.boxManager?.focusBox({ appId: focused });
|
296
|
-
// 确保 focus 修改的时候, appProxy 已经创建
|
297
|
-
setTimeout(() => {
|
298
|
-
const appProxy = this.appProxies.get(focused);
|
299
|
-
if (appProxy) {
|
300
|
-
appRegister.notifyApp(appProxy.kind, "focus", { appId: focused });
|
301
|
-
}
|
302
|
-
}, 0);
|
303
|
-
}
|
304
|
-
}
|
286
|
+
this.onFocusChange(focused);
|
305
287
|
});
|
306
288
|
});
|
307
289
|
this.refresher?.add("registeredChange", () => {
|
@@ -329,6 +311,35 @@ export class AppManager {
|
|
329
311
|
});
|
330
312
|
}
|
331
313
|
|
314
|
+
private onMainViewIndexChange = (index: number) => {
|
315
|
+
if (index !== undefined && this._prevSceneIndex !== index) {
|
316
|
+
callbacks.emit("mainViewSceneIndexChange", index);
|
317
|
+
emitter.emit("changePageState");
|
318
|
+
if (this.callbacksNode) {
|
319
|
+
this.updateSceneState(this.callbacksNode);
|
320
|
+
}
|
321
|
+
this._prevSceneIndex = index;
|
322
|
+
}
|
323
|
+
}
|
324
|
+
|
325
|
+
private onFocusChange = (focused: string | undefined) => {
|
326
|
+
if (this._prevFocused !== focused) {
|
327
|
+
callbacks.emit("focusedChange", focused);
|
328
|
+
emitter.emit("focusedChange", { focused, prev: this._prevFocused });
|
329
|
+
this._prevFocused = focused;
|
330
|
+
if (focused !== undefined) {
|
331
|
+
this.boxManager?.focusBox({ appId: focused });
|
332
|
+
// 确保 focus 修改的时候, appProxy 已经创建
|
333
|
+
setTimeout(() => {
|
334
|
+
const appProxy = this.appProxies.get(focused);
|
335
|
+
if (appProxy) {
|
336
|
+
appRegister.notifyApp(appProxy.kind, "focus", { appId: focused });
|
337
|
+
}
|
338
|
+
}, 0);
|
339
|
+
}
|
340
|
+
}
|
341
|
+
}
|
342
|
+
|
332
343
|
/**
|
333
344
|
* 插件更新 attributes 时的回调
|
334
345
|
*
|
@@ -717,7 +728,7 @@ export class AppManager {
|
|
717
728
|
});
|
718
729
|
}
|
719
730
|
|
720
|
-
public dispatchInternalEvent(event: Events, payload
|
731
|
+
public dispatchInternalEvent(event: Events, payload?: any) {
|
721
732
|
this.safeDispatchMagixEvent(MagixEventName, {
|
722
733
|
eventName: event,
|
723
734
|
payload: payload,
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import type { ScenesCallbacks, ScenesCallbacksNode } from "white-web-sdk";
|
2
|
+
import type { AppManager } from "../AppManager";
|
3
|
+
|
4
|
+
export class ScenesCallbackManager {
|
5
|
+
|
6
|
+
private nodes: Map<string, ScenesCallbacksNode> = new Map();
|
7
|
+
|
8
|
+
constructor(private manager: AppManager) {}
|
9
|
+
|
10
|
+
public createNode(path: string, callbacks?: Partial<ScenesCallbacks>): ScenesCallbacksNode | null {
|
11
|
+
const node = this.manager.displayer.createScenesCallback(path, callbacks);
|
12
|
+
if (node) {
|
13
|
+
this.nodes.set(path, node);
|
14
|
+
}
|
15
|
+
return node;
|
16
|
+
}
|
17
|
+
|
18
|
+
public getScenes(path: string) {
|
19
|
+
const node = this.nodes.get(path);
|
20
|
+
return node?.scenes;
|
21
|
+
}
|
22
|
+
|
23
|
+
public getScenesOnce(path: string) {
|
24
|
+
let node = this.nodes.get(path);
|
25
|
+
if (!node) {
|
26
|
+
const created = this.createNode(path);
|
27
|
+
if (created) {
|
28
|
+
node = created;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
const scenes = node?.scenes;
|
32
|
+
this.removeNode(path);
|
33
|
+
return scenes;
|
34
|
+
}
|
35
|
+
|
36
|
+
public removeNode(path: string) {
|
37
|
+
const node = this.nodes.get(path);
|
38
|
+
if (node) {
|
39
|
+
node.dispose();
|
40
|
+
this.nodes.delete(path);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
public destroy(): void {
|
45
|
+
this.nodes.forEach(node => node.dispose());
|
46
|
+
}
|
47
|
+
}
|
package/src/View/MainView.ts
CHANGED
@@ -22,7 +22,6 @@ export class MainViewProxy {
|
|
22
22
|
this.mainView = this.createMainView();
|
23
23
|
this.moveCameraSizeByAttributes();
|
24
24
|
emitter.once("mainViewMounted").then(() => {
|
25
|
-
this.addMainViewListener();
|
26
25
|
setTimeout(() => {
|
27
26
|
this.start();
|
28
27
|
if (!this.mainViewCamera || !this.mainViewSize) {
|
@@ -55,6 +54,7 @@ export class MainViewProxy {
|
|
55
54
|
public start() {
|
56
55
|
if (this.started) return;
|
57
56
|
this.sizeChangeHandler(this.mainViewSize);
|
57
|
+
this.addMainViewListener();
|
58
58
|
this.addCameraListener();
|
59
59
|
this.manager.refresher?.add(Fields.MainViewCamera, this.cameraReaction);
|
60
60
|
this.started = true;
|
@@ -143,6 +143,7 @@ export class MainViewProxy {
|
|
143
143
|
this.view.divElement.removeEventListener("click", this.mainViewClickListener);
|
144
144
|
this.view.divElement.removeEventListener("touchend", this.mainViewClickListener);
|
145
145
|
}
|
146
|
+
this.mainViewIsAddListener = false;
|
146
147
|
}
|
147
148
|
|
148
149
|
private mainViewClickListener = () => {
|
package/src/constants.ts
CHANGED
package/src/index.ts
CHANGED
@@ -553,9 +553,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
|
|
553
553
|
* 设置 ViewMode
|
554
554
|
*/
|
555
555
|
public setViewMode(mode: ViewMode): void {
|
556
|
-
if (!this.canOperate) return;
|
557
556
|
if (mode === ViewMode.Broadcaster) {
|
558
|
-
this.
|
557
|
+
if (this.canOperate) {
|
558
|
+
this.appManager?.mainViewProxy.setCameraAndSize();
|
559
|
+
}
|
559
560
|
this.appManager?.mainViewProxy.start();
|
560
561
|
}
|
561
562
|
if (mode === ViewMode.Freedom) {
|