@netless/window-manager 1.0.0-canary.2 → 1.0.0-canary.22
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/__mocks__/white-web-sdk.ts +10 -1
- package/dist/App/AppContext.d.ts +11 -7
- package/dist/App/AppProxy.d.ts +35 -7
- package/dist/App/{WhiteBoardView.d.ts → WhiteboardView.d.ts} +10 -1
- package/dist/App/index.d.ts +2 -1
- package/dist/App/type.d.ts +21 -0
- package/dist/AppManager.d.ts +5 -5
- package/dist/AttributesDelegate.d.ts +11 -16
- package/dist/BoxManager.d.ts +7 -6
- package/dist/Cursor/index.d.ts +0 -1
- package/dist/InternalEmitter.d.ts +3 -2
- package/dist/Page/PageController.d.ts +1 -0
- package/dist/ReconnectRefresher.d.ts +1 -1
- package/dist/Utils/Common.d.ts +1 -0
- package/dist/View/CameraSynchronizer.d.ts +9 -9
- package/dist/View/MainView.d.ts +18 -7
- package/dist/View/ViewSync.d.ts +24 -0
- package/dist/constants.d.ts +6 -2
- package/dist/index.cjs.js +12 -12
- package/dist/index.d.ts +19 -2
- package/dist/index.es.js +803 -425
- package/dist/index.umd.js +12 -12
- package/dist/style.css +1 -1
- package/docs/app-context.md +98 -64
- package/docs/develop-app.md +2 -5
- package/docs/mirgrate-to-1.0.md +28 -0
- package/package.json +3 -3
- package/pnpm-lock.yaml +9 -9
- package/src/App/AppContext.ts +43 -21
- package/src/App/AppProxy.ts +247 -79
- package/src/App/{WhiteBoardView.ts → WhiteboardView.ts} +38 -4
- package/src/App/index.ts +2 -1
- package/src/App/type.ts +22 -0
- package/src/AppManager.ts +38 -31
- package/src/AttributesDelegate.ts +18 -18
- package/src/BoxManager.ts +28 -22
- package/src/Cursor/index.ts +0 -2
- package/src/InternalEmitter.ts +3 -2
- package/src/Page/PageController.ts +1 -0
- package/src/PageState.ts +1 -1
- package/src/ReconnectRefresher.ts +7 -2
- package/src/Utils/Common.ts +6 -0
- package/src/Utils/Reactive.ts +27 -26
- package/src/Utils/RoomHacker.ts +3 -0
- package/src/View/CameraSynchronizer.ts +43 -30
- package/src/View/MainView.ts +106 -81
- package/src/View/ViewSync.ts +110 -0
- package/src/constants.ts +5 -1
- package/src/index.ts +59 -15
- package/src/style.css +8 -0
package/src/Utils/Reactive.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
import { listenUpdated, unlistenUpdated, reaction, UpdateEventKind } from "white-web-sdk";
|
2
|
-
import type { AkkoObjectUpdatedProperty , AkkoObjectUpdatedListener } from "white-web-sdk";
|
3
1
|
import { isObject } from "lodash";
|
2
|
+
import { listenUpdated, reaction, unlistenUpdated, UpdateEventKind } from "white-web-sdk";
|
3
|
+
import type { AkkoObjectUpdatedProperty, AkkoObjectUpdatedListener } from "white-web-sdk";
|
4
4
|
|
5
5
|
// 兼容 13 和 14 版本 SDK
|
6
6
|
export const onObjectByEvent = (event: UpdateEventKind) => {
|
@@ -12,7 +12,7 @@ export const onObjectByEvent = (event: UpdateEventKind) => {
|
|
12
12
|
if (kinds.includes(event)) {
|
13
13
|
func();
|
14
14
|
}
|
15
|
-
}
|
15
|
+
};
|
16
16
|
listenUpdated(object, listener);
|
17
17
|
func();
|
18
18
|
return () => unlistenUpdated(object, listener);
|
@@ -21,43 +21,44 @@ export const onObjectByEvent = (event: UpdateEventKind) => {
|
|
21
21
|
() => object,
|
22
22
|
() => {
|
23
23
|
func();
|
24
|
-
},
|
24
|
+
},
|
25
|
+
{
|
25
26
|
fireImmediately: true,
|
26
27
|
}
|
27
|
-
)
|
28
|
+
);
|
28
29
|
}
|
29
|
-
}
|
30
|
-
}
|
30
|
+
};
|
31
|
+
};
|
31
32
|
|
32
33
|
export const safeListenPropsUpdated = <T>(
|
33
34
|
getProps: () => T,
|
34
35
|
callback: AkkoObjectUpdatedListener<T>,
|
35
36
|
onDestroyed?: (props: unknown) => void
|
36
|
-
|
37
|
+
) => {
|
37
38
|
let disposeListenUpdated: (() => void) | null = null;
|
38
39
|
const disposeReaction = reaction(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
40
|
+
getProps,
|
41
|
+
() => {
|
42
|
+
if (disposeListenUpdated) {
|
43
|
+
disposeListenUpdated();
|
44
|
+
disposeListenUpdated = null;
|
45
|
+
}
|
46
|
+
const props = getProps();
|
47
|
+
if (isObject(props)) {
|
48
|
+
disposeListenUpdated = () => unlistenUpdated(props, callback);
|
49
|
+
listenUpdated(props, callback);
|
50
|
+
} else {
|
51
|
+
onDestroyed?.(props);
|
52
|
+
}
|
53
|
+
},
|
54
|
+
{ fireImmediately: true }
|
54
55
|
);
|
55
56
|
|
56
57
|
return () => {
|
57
|
-
|
58
|
-
|
58
|
+
disposeListenUpdated?.();
|
59
|
+
disposeReaction();
|
59
60
|
};
|
60
|
-
}
|
61
|
+
};
|
61
62
|
|
62
63
|
export const onObjectRemoved = onObjectByEvent(UpdateEventKind.Removed);
|
63
64
|
export const onObjectInserted = onObjectByEvent(UpdateEventKind.Inserted);
|
package/src/Utils/RoomHacker.ts
CHANGED
@@ -56,6 +56,9 @@ export const replaceRoomFunction = (room: Room | Player, manager: WindowManager)
|
|
56
56
|
room.lockImages = (...args) => manager.lockImages(...args);
|
57
57
|
|
58
58
|
delegateRemoveScenes(room, manager);
|
59
|
+
if (!(room as any).dynamicPpt.slideStateAdapter.pptHandler) {
|
60
|
+
(room as any).dynamicPpt.slideStateAdapter.pptHandler = manager.createPPTHandler();
|
61
|
+
}
|
59
62
|
}
|
60
63
|
};
|
61
64
|
|
@@ -1,32 +1,32 @@
|
|
1
1
|
import { AnimationMode } from "white-web-sdk";
|
2
|
-
import { delay, throttle } from "lodash";
|
2
|
+
import { debounce, delay, isEqual, pick, throttle } from "lodash";
|
3
3
|
import type { TeleBoxRect } from "@netless/telebox-insider";
|
4
|
-
import type { Camera, View
|
5
|
-
import type {
|
4
|
+
import type { Camera, View } from "white-web-sdk";
|
5
|
+
import type { ICamera, ISize } from "../AttributesDelegate";
|
6
6
|
|
7
|
-
export type SaveCamera = (camera:
|
7
|
+
export type SaveCamera = (camera: ICamera) => void;
|
8
8
|
|
9
9
|
export class CameraSynchronizer {
|
10
|
-
|
11
|
-
|
10
|
+
public remoteCamera?: ICamera;
|
11
|
+
public remoteSize?: ISize;
|
12
12
|
protected rect?: TeleBoxRect;
|
13
13
|
protected view?: View;
|
14
14
|
|
15
15
|
constructor(protected saveCamera: SaveCamera) {}
|
16
16
|
|
17
|
-
public setRect(rect: TeleBoxRect) {
|
17
|
+
public setRect = debounce((rect: TeleBoxRect) => {
|
18
18
|
this.rect = rect;
|
19
19
|
if (this.remoteCamera && this.remoteSize) {
|
20
20
|
this.onRemoteUpdate(this.remoteCamera, this.remoteSize);
|
21
21
|
}
|
22
|
-
}
|
22
|
+
}, 10);
|
23
23
|
|
24
24
|
public setView(view: View) {
|
25
25
|
this.view = view;
|
26
26
|
}
|
27
27
|
|
28
28
|
// 远端 Camera 或者 size 更新
|
29
|
-
public onRemoteUpdate = throttle((camera:
|
29
|
+
public onRemoteUpdate = throttle((camera: ICamera, size: ISize) => {
|
30
30
|
this.remoteCamera = camera;
|
31
31
|
this.remoteSize = size;
|
32
32
|
if (this.remoteSize && this.rect) {
|
@@ -37,31 +37,44 @@ export class CameraSynchronizer {
|
|
37
37
|
scale = this.rect.height / size.height;
|
38
38
|
}
|
39
39
|
const nextScale = camera.scale * scale;
|
40
|
-
const moveCamera = () =>
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
const moveCamera = () => {
|
41
|
+
const config: Partial<Camera> & { animationMode: AnimationMode } = {
|
42
|
+
scale: nextScale,
|
43
|
+
animationMode: AnimationMode.Immediately,
|
44
|
+
}
|
45
|
+
if (camera.centerX !== null) {
|
46
|
+
config.centerX = camera.centerX;
|
47
|
+
}
|
48
|
+
if (camera.centerY !== null) {
|
49
|
+
config.centerY = camera.centerY;
|
50
|
+
}
|
51
|
+
this.view?.moveCamera(config);
|
52
|
+
}
|
53
|
+
moveCamera();
|
46
54
|
// TODO 直接调用 moveCamera 依然会出现 camera 错误的情况,这里暂时加一个 delay 保证 camera 是对的, 后续需要 SDK 进行修改
|
47
|
-
delay(moveCamera,
|
55
|
+
delay(moveCamera, 50);
|
48
56
|
}
|
49
|
-
},
|
50
|
-
|
51
|
-
|
52
|
-
public onLocalCameraUpdate(camera: Camera) {
|
53
|
-
this.saveCamera(camera);
|
54
|
-
}
|
57
|
+
}, 10);
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
+
public onRemoteSizeUpdate(size: ISize) {
|
60
|
+
this.remoteSize = size;
|
61
|
+
const needMoveCamera = !isEqual(pick(this.rect, ["width", "height"]), pick(size, ["width", "height"]));
|
62
|
+
if (this.rect && this.remoteCamera && needMoveCamera) {
|
59
63
|
const scale = this.rect.width / size.width;
|
60
|
-
const nextScale = this.
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
64
|
+
const nextScale = this.remoteCamera.scale * scale;
|
65
|
+
const moveCamera = () => {
|
66
|
+
this.view?.moveCamera({
|
67
|
+
scale: nextScale,
|
68
|
+
animationMode: AnimationMode.Immediately,
|
69
|
+
})
|
70
|
+
};
|
71
|
+
moveCamera();
|
72
|
+
delay(moveCamera, 50);
|
65
73
|
}
|
66
74
|
}
|
75
|
+
|
76
|
+
public onLocalCameraUpdate(camera: ICamera) {
|
77
|
+
this.saveCamera(camera);
|
78
|
+
this.remoteCamera = camera;
|
79
|
+
}
|
67
80
|
}
|
package/src/View/MainView.ts
CHANGED
@@ -1,73 +1,96 @@
|
|
1
|
-
import { reaction } from "white-web-sdk";
|
2
1
|
import { callbacks } from "../callback";
|
3
2
|
import { createView } from "./ViewManager";
|
4
3
|
import { debounce, get, isEqual } from "lodash";
|
5
4
|
import { emitter } from "../InternalEmitter";
|
6
5
|
import { Events } from "../constants";
|
7
6
|
import { Fields } from "../AttributesDelegate";
|
8
|
-
import {
|
7
|
+
import { reaction, toJS } from "white-web-sdk";
|
8
|
+
import { releaseView, setScenePath, setViewFocusScenePath } from "../Utils/Common";
|
9
9
|
import { SideEffectManager } from "side-effect-manager";
|
10
|
-
import
|
10
|
+
import { Val } from "value-enhancer";
|
11
|
+
import { ViewSync } from "./ViewSync";
|
12
|
+
import type { ICamera, ISize } from "../AttributesDelegate";
|
13
|
+
import type { Size, View } from "white-web-sdk";
|
11
14
|
import type { AppManager } from "../AppManager";
|
12
|
-
import { CameraSynchronizer } from "./CameraSynchronizer";
|
13
15
|
|
14
16
|
export class MainViewProxy {
|
15
17
|
private started = false;
|
16
18
|
private mainViewIsAddListener = false;
|
17
19
|
private mainView: View;
|
18
20
|
private store = this.manager.store;
|
19
|
-
private synchronizer: CameraSynchronizer;
|
20
21
|
|
21
22
|
private sideEffectManager = new SideEffectManager();
|
22
23
|
|
24
|
+
public camera$ = new Val<ICamera | undefined>(undefined);
|
25
|
+
public size$ = new Val<ISize | undefined>(undefined);
|
26
|
+
public view$ = new Val<View | undefined>(undefined);
|
27
|
+
|
28
|
+
public viewSync?: ViewSync;
|
29
|
+
|
23
30
|
constructor(private manager: AppManager) {
|
24
|
-
this.synchronizer = new CameraSynchronizer(
|
25
|
-
camera => this.store.setMainViewCamera({ ...camera, id: this.manager.uid })
|
26
|
-
);
|
27
31
|
this.mainView = this.createMainView();
|
28
|
-
this.moveCameraSizeByAttributes();
|
29
32
|
emitter.once("mainViewMounted").then(() => {
|
30
33
|
this.addMainViewListener();
|
31
34
|
this.start();
|
32
35
|
this.ensureCameraAndSize();
|
33
36
|
this.startListenWritableChange();
|
34
37
|
});
|
35
|
-
this.sideEffectManager.add(() =>
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
this.sideEffectManager.add(() => [
|
39
|
+
emitter.on("startReconnect", () => {
|
40
|
+
releaseView(this.mainView);
|
41
|
+
}),
|
42
|
+
]);
|
43
|
+
this.createViewSync();
|
44
|
+
this.sideEffectManager.add(() => emitter.on("focusedChange", ({ focused }) => {
|
45
|
+
if (focused === undefined) {
|
46
|
+
const scenePath = this.store.getMainViewScenePath();
|
47
|
+
if (scenePath) {
|
48
|
+
setScenePath(this.manager.room, scenePath);
|
42
49
|
}
|
50
|
+
}
|
51
|
+
}));
|
52
|
+
}
|
53
|
+
|
54
|
+
public createViewSync = () => {
|
55
|
+
if (this.manager.boxManager && !this.viewSync) {
|
56
|
+
this.viewSync = new ViewSync({
|
57
|
+
uid: this.manager.uid,
|
58
|
+
view$: this.view$,
|
59
|
+
camera$: this.camera$,
|
60
|
+
size$: this.size$,
|
61
|
+
stageRect$: this.manager.boxManager?.stageRect$,
|
62
|
+
viewMode$: this.manager.windowManger.viewMode$,
|
63
|
+
storeCamera: this.storeCamera,
|
64
|
+
storeSize: this.storeSize,
|
43
65
|
});
|
44
|
-
});
|
45
|
-
const rect = this.manager.boxManager?.stageRect;
|
46
|
-
if (rect) {
|
47
|
-
this.synchronizer.setRect(rect);
|
48
66
|
}
|
49
|
-
|
50
|
-
return emitter.on("playgroundSizeChange", rect => {
|
51
|
-
this.synchronizer.setRect(rect);
|
52
|
-
this.synchronizer.onLocalSizeUpdate(rect);
|
53
|
-
});
|
54
|
-
});
|
55
|
-
}
|
67
|
+
};
|
56
68
|
|
57
69
|
private startListenWritableChange = () => {
|
58
|
-
this.sideEffectManager.add(() =>
|
59
|
-
|
70
|
+
this.sideEffectManager.add(() =>
|
71
|
+
emitter.on("writableChange", isWritable => {
|
60
72
|
if (isWritable) {
|
61
73
|
this.ensureCameraAndSize();
|
62
74
|
}
|
63
|
-
})
|
64
|
-
|
75
|
+
})
|
76
|
+
);
|
65
77
|
};
|
66
78
|
|
67
79
|
public ensureCameraAndSize() {
|
68
80
|
if (!this.mainViewCamera || !this.mainViewSize) {
|
69
81
|
this.manager.dispatchInternalEvent(Events.InitMainViewCamera);
|
70
|
-
this.
|
82
|
+
this.storeCamera({
|
83
|
+
id: this.manager.uid,
|
84
|
+
...this.view.camera
|
85
|
+
});
|
86
|
+
const stageRect = this.manager.boxManager?.stageRect;
|
87
|
+
if (stageRect && !this.mainViewSize) {
|
88
|
+
this.storeSize({
|
89
|
+
id: this.manager.uid,
|
90
|
+
width: stageRect.width,
|
91
|
+
height: stageRect.height
|
92
|
+
});
|
93
|
+
}
|
71
94
|
}
|
72
95
|
}
|
73
96
|
|
@@ -83,55 +106,73 @@ export class MainViewProxy {
|
|
83
106
|
return get(this.view, ["didRelease"]);
|
84
107
|
}
|
85
108
|
|
86
|
-
private moveCameraSizeByAttributes() {
|
87
|
-
this.synchronizer.onRemoteUpdate(this.mainViewCamera, this.mainViewSize);
|
88
|
-
}
|
89
|
-
|
90
109
|
public start() {
|
91
110
|
if (this.started) return;
|
92
|
-
this.sizeChangeHandler(this.mainViewSize);
|
93
111
|
this.addCameraListener();
|
94
112
|
this.addCameraReaction();
|
95
113
|
this.started = true;
|
96
114
|
}
|
97
115
|
|
98
116
|
public addCameraReaction = () => {
|
99
|
-
this.manager.refresher
|
117
|
+
this.manager.refresher.add(Fields.MainViewCamera, this.cameraReaction);
|
118
|
+
this.manager.refresher.add(Fields.MainViewSize, this.sizeReaction);
|
100
119
|
};
|
101
120
|
|
102
|
-
public
|
103
|
-
const
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
121
|
+
public storeCurrentCamera = () => {
|
122
|
+
const iCamera = this.view.camera;
|
123
|
+
this.storeCamera({
|
124
|
+
id: this.manager.uid,
|
125
|
+
...iCamera
|
126
|
+
});
|
127
|
+
}
|
128
|
+
|
129
|
+
public storeCurrentSize = () => {
|
130
|
+
const rect = this.manager.boxManager?.stageRect;
|
131
|
+
if (rect) {
|
132
|
+
this.storeSize({
|
133
|
+
id: this.manager.uid,
|
134
|
+
width: rect.width,
|
135
|
+
height: rect.height
|
136
|
+
});
|
108
137
|
}
|
109
138
|
}
|
110
139
|
|
140
|
+
public storeCamera = (camera: ICamera) => {
|
141
|
+
this.store.setMainViewCamera(camera);
|
142
|
+
};
|
143
|
+
|
144
|
+
public storeSize = (size: ISize) => {
|
145
|
+
this.store.setMainViewSize(size);
|
146
|
+
};
|
147
|
+
|
111
148
|
private cameraReaction = () => {
|
112
149
|
return reaction(
|
113
150
|
() => this.mainViewCamera,
|
114
151
|
camera => {
|
115
|
-
if (camera
|
116
|
-
|
152
|
+
if (camera) {
|
153
|
+
const rawCamera = toJS(camera);
|
154
|
+
if (!isEqual(rawCamera, this.camera$.value)) {
|
155
|
+
this.camera$.setValue(rawCamera);
|
156
|
+
}
|
117
157
|
}
|
118
158
|
},
|
119
159
|
{ fireImmediately: true }
|
120
160
|
);
|
121
161
|
};
|
122
162
|
|
123
|
-
|
124
|
-
|
125
|
-
this.
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
163
|
+
private sizeReaction = () => {
|
164
|
+
return reaction(
|
165
|
+
() => this.mainViewSize,
|
166
|
+
size => {
|
167
|
+
if (size) {
|
168
|
+
const rawSize = toJS(size);
|
169
|
+
if (!isEqual(rawSize, this.size$.value)) {
|
170
|
+
this.size$.setValue(rawSize);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
},
|
174
|
+
{ fireImmediately: true }
|
175
|
+
);
|
135
176
|
};
|
136
177
|
|
137
178
|
public get view(): View {
|
@@ -148,7 +189,7 @@ export class MainViewProxy {
|
|
148
189
|
if (mainViewScenePath) {
|
149
190
|
setViewFocusScenePath(mainView, mainViewScenePath);
|
150
191
|
}
|
151
|
-
this.
|
192
|
+
this.view$.setValue(mainView);
|
152
193
|
return mainView;
|
153
194
|
}
|
154
195
|
|
@@ -171,9 +212,7 @@ export class MainViewProxy {
|
|
171
212
|
const divElement = this.mainView.divElement;
|
172
213
|
const disableCameraTransform = this.mainView.disableCameraTransform;
|
173
214
|
this.stop();
|
174
|
-
|
175
|
-
this.mainView.release();
|
176
|
-
}
|
215
|
+
releaseView(this.mainView);
|
177
216
|
this.removeMainViewListener();
|
178
217
|
this.mainView = this.createMainView();
|
179
218
|
this.mainView.disableCameraTransform = disableCameraTransform;
|
@@ -182,21 +221,6 @@ export class MainViewProxy {
|
|
182
221
|
this.start();
|
183
222
|
}
|
184
223
|
|
185
|
-
private onCameraUpdatedByDevice = (camera: Camera) => {
|
186
|
-
this.synchronizer.onLocalCameraUpdate(camera);
|
187
|
-
const size = this.getStageSize();
|
188
|
-
if (size && !isEqual(size, this.mainViewSize)) {
|
189
|
-
this.setMainViewSize(size);
|
190
|
-
}
|
191
|
-
};
|
192
|
-
|
193
|
-
private getStageSize(): Size | undefined {
|
194
|
-
const stage = this.manager.boxManager?.stageRect;
|
195
|
-
if (stage) {
|
196
|
-
return { width: stage.width, height: stage.height };
|
197
|
-
}
|
198
|
-
}
|
199
|
-
|
200
224
|
public addMainViewListener(): void {
|
201
225
|
if (this.mainViewIsAddListener) return;
|
202
226
|
if (this.view.divElement) {
|
@@ -229,13 +253,11 @@ export class MainViewProxy {
|
|
229
253
|
}, 50);
|
230
254
|
|
231
255
|
private addCameraListener() {
|
232
|
-
this.view.callbacks.on("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
|
233
256
|
this.view.callbacks.on("onCameraUpdated", this.onCameraOrSizeUpdated);
|
234
257
|
this.view.callbacks.on("onSizeUpdated", this.onCameraOrSizeUpdated);
|
235
258
|
}
|
236
259
|
|
237
260
|
private removeCameraListener() {
|
238
|
-
this.view.callbacks.off("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
|
239
261
|
this.view.callbacks.off("onCameraUpdated", this.onCameraOrSizeUpdated);
|
240
262
|
this.view.callbacks.off("onSizeUpdated", this.onCameraOrSizeUpdated);
|
241
263
|
}
|
@@ -246,12 +268,15 @@ export class MainViewProxy {
|
|
246
268
|
|
247
269
|
public stop() {
|
248
270
|
this.removeCameraListener();
|
249
|
-
this.manager.refresher
|
250
|
-
this.manager.refresher
|
271
|
+
this.manager.refresher.remove(Fields.MainViewCamera);
|
272
|
+
this.manager.refresher.remove(Fields.MainViewSize);
|
251
273
|
this.started = false;
|
252
274
|
}
|
253
275
|
|
254
276
|
public destroy() {
|
277
|
+
this.camera$.destroy();
|
278
|
+
this.size$.destroy();
|
279
|
+
this.view$.destroy();
|
255
280
|
this.removeMainViewListener();
|
256
281
|
this.stop();
|
257
282
|
this.sideEffectManager.flushAll();
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import { AnimationMode, ViewMode } from "white-web-sdk";
|
2
|
+
import { CameraSynchronizer } from "./CameraSynchronizer";
|
3
|
+
import { combine } from "value-enhancer";
|
4
|
+
import { isEqual } from "lodash";
|
5
|
+
import { SideEffectManager } from "side-effect-manager";
|
6
|
+
import type { Camera, View } from "white-web-sdk";
|
7
|
+
import type { Val, ReadonlyVal } from "value-enhancer";
|
8
|
+
import type { ICamera, ISize } from "../AttributesDelegate";
|
9
|
+
import type { TeleBoxRect } from "@netless/telebox-insider";
|
10
|
+
|
11
|
+
export type ViewSyncContext = {
|
12
|
+
uid: string;
|
13
|
+
// 远端 camera
|
14
|
+
camera$: Val<ICamera | undefined, boolean>;
|
15
|
+
// 远端 size
|
16
|
+
size$: Val<ISize | undefined>;
|
17
|
+
|
18
|
+
stageRect$: ReadonlyVal<TeleBoxRect>;
|
19
|
+
|
20
|
+
viewMode$?: Val<ViewMode>;
|
21
|
+
|
22
|
+
storeCamera: (camera: ICamera) => void;
|
23
|
+
|
24
|
+
storeSize: (size: ISize) => void;
|
25
|
+
|
26
|
+
view$: Val<View | undefined>;
|
27
|
+
};
|
28
|
+
|
29
|
+
export class ViewSync {
|
30
|
+
private sem = new SideEffectManager();
|
31
|
+
private synchronizer: CameraSynchronizer;
|
32
|
+
|
33
|
+
constructor(private context: ViewSyncContext) {
|
34
|
+
this.synchronizer = new CameraSynchronizer((camera: ICamera) => {
|
35
|
+
this.context.camera$.setValue(camera, true);
|
36
|
+
const notStoreCamera =
|
37
|
+
this.context.viewMode$ && this.context.viewMode$.value === ViewMode.Freedom;
|
38
|
+
if (notStoreCamera) {
|
39
|
+
return;
|
40
|
+
} else {
|
41
|
+
this.context.storeCamera(camera);
|
42
|
+
}
|
43
|
+
});
|
44
|
+
this.bindView(this.context.view$.value);
|
45
|
+
this.sem.add(() => [
|
46
|
+
this.context.view$.subscribe(view => {
|
47
|
+
const currentCamera = this.context.camera$.value;
|
48
|
+
if (currentCamera && this.context.size$.value) {
|
49
|
+
view?.moveCamera({
|
50
|
+
scale: 1,
|
51
|
+
animationMode: AnimationMode.Immediately,
|
52
|
+
});
|
53
|
+
this.synchronizer.onRemoteUpdate(currentCamera, this.context.size$.value);
|
54
|
+
}
|
55
|
+
|
56
|
+
this.bindView(view);
|
57
|
+
}),
|
58
|
+
this.context.camera$.subscribe((camera, skipUpdate) => {
|
59
|
+
const size = this.context.size$.value;
|
60
|
+
if (camera && size && !skipUpdate) {
|
61
|
+
this.synchronizer.onRemoteUpdate(camera, size);
|
62
|
+
}
|
63
|
+
}),
|
64
|
+
this.context.size$.subscribe(size => {
|
65
|
+
if (size) {
|
66
|
+
this.synchronizer.onRemoteSizeUpdate(size);
|
67
|
+
}
|
68
|
+
}),
|
69
|
+
this.context.stageRect$.reaction(rect => {
|
70
|
+
if (rect) {
|
71
|
+
this.synchronizer.setRect(rect);
|
72
|
+
}
|
73
|
+
})
|
74
|
+
]);
|
75
|
+
const camera$size$ = combine([this.context.camera$, this.context.size$]);
|
76
|
+
camera$size$.reaction(([camera, size]) => {
|
77
|
+
if (camera && size) {
|
78
|
+
this.synchronizer.onRemoteUpdate(camera, size);
|
79
|
+
camera$size$.destroy();
|
80
|
+
}
|
81
|
+
});
|
82
|
+
}
|
83
|
+
|
84
|
+
public bindView = (view?: View) => {
|
85
|
+
if (!view) return;
|
86
|
+
this.synchronizer.setView(view);
|
87
|
+
this.sem.flush("view");
|
88
|
+
this.sem.add(() => {
|
89
|
+
view.callbacks.on("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
|
90
|
+
return () =>
|
91
|
+
view.callbacks.off("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
|
92
|
+
}, "view");
|
93
|
+
};
|
94
|
+
|
95
|
+
private onCameraUpdatedByDevice = (camera: Camera) => {
|
96
|
+
if (!camera) return;
|
97
|
+
this.synchronizer.onLocalCameraUpdate({ ...camera, id: this.context.uid });
|
98
|
+
const stage = this.context.stageRect$.value;
|
99
|
+
if (stage) {
|
100
|
+
const size = { width: stage.width, height: stage.height, id: this.context.uid };
|
101
|
+
if (!isEqual(size, this.context.size$.value)) {
|
102
|
+
this.context.storeSize(size);
|
103
|
+
}
|
104
|
+
}
|
105
|
+
};
|
106
|
+
|
107
|
+
public destroy() {
|
108
|
+
this.sem.flushAll();
|
109
|
+
}
|
110
|
+
}
|
package/src/constants.ts
CHANGED
@@ -5,7 +5,6 @@ export enum Events {
|
|
5
5
|
AppBoxStateChange = "AppBoxStateChange",
|
6
6
|
GetAttributes = "GetAttributes",
|
7
7
|
UpdateWindowManagerWrapper = "UpdateWindowManagerWrapper",
|
8
|
-
InitReplay = "InitReplay",
|
9
8
|
WindowCreated = "WindowCreated",
|
10
9
|
SetMainViewScenePath = "SetMainViewScenePath",
|
11
10
|
SetMainViewSceneIndex = "SetMainViewSceneIndex",
|
@@ -27,6 +26,11 @@ export enum AppAttributes {
|
|
27
26
|
Position = "position",
|
28
27
|
SceneIndex = "SceneIndex",
|
29
28
|
ZIndex = "zIndex",
|
29
|
+
Visible = "visible",
|
30
|
+
Ratio = "ratio",
|
31
|
+
StageRatio = "stageRatio",
|
32
|
+
Draggable = "draggable",
|
33
|
+
Resizable = "resizable",
|
30
34
|
}
|
31
35
|
|
32
36
|
export enum AppEvents {
|