@netless/window-manager 1.0.0-canary.2 → 1.0.0-canary.20
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 +6 -6
- package/dist/App/AppProxy.d.ts +30 -5
- package/dist/App/{WhiteBoardView.d.ts → WhiteboardView.d.ts} +10 -1
- package/dist/App/index.d.ts +1 -1
- package/dist/AppManager.d.ts +5 -5
- package/dist/AttributesDelegate.d.ts +11 -16
- package/dist/BoxManager.d.ts +3 -3
- package/dist/InternalEmitter.d.ts +2 -0
- 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/Utils/Reactive.d.ts +2 -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 -1
- package/dist/index.cjs.js +12 -12
- package/dist/index.d.ts +19 -2
- package/dist/index.es.js +791 -380
- 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 +30 -19
- package/src/App/AppProxy.ts +251 -39
- package/src/App/{WhiteBoardView.ts → WhiteboardView.ts} +38 -4
- package/src/App/index.ts +1 -1
- package/src/AppManager.ts +33 -30
- package/src/AttributesDelegate.ts +18 -18
- package/src/BoxManager.ts +20 -15
- package/src/InternalEmitter.ts +2 -0
- package/src/Page/PageController.ts +1 -0
- package/src/PageState.ts +1 -1
- package/src/ReconnectRefresher.ts +2 -1
- package/src/Utils/Common.ts +6 -0
- package/src/Utils/Reactive.ts +43 -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 +116 -0
- package/src/constants.ts +5 -0
- package/src/index.ts +59 -15
- package/src/style.css +8 -0
package/src/App/AppContext.ts
CHANGED
@@ -17,7 +17,6 @@ import type {
|
|
17
17
|
} from "white-web-sdk";
|
18
18
|
import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
19
19
|
import type Emittery from "emittery";
|
20
|
-
import type { BoxManager } from "../BoxManager";
|
21
20
|
import type { AppEmitterEvent, Member } from "../index";
|
22
21
|
import type { AppManager } from "../AppManager";
|
23
22
|
import type { AppProxy } from "./AppProxy";
|
@@ -26,10 +25,9 @@ import type {
|
|
26
25
|
MagixEventDispatcher,
|
27
26
|
MagixEventRemoveListener,
|
28
27
|
} from "./MagixEvent";
|
29
|
-
import { WhiteBoardView } from "./
|
28
|
+
import { WhiteBoardView } from "./WhiteboardView";
|
30
29
|
import { findMemberByUid } from "../Helper";
|
31
30
|
import { MAX_PAGE_SIZE } from "../constants";
|
32
|
-
import { putScenes } from "../Utils/Common";
|
33
31
|
import { isNumber } from "lodash";
|
34
32
|
|
35
33
|
export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOptions = any> {
|
@@ -49,11 +47,11 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
49
47
|
private store = this.manager.store;
|
50
48
|
public readonly isAddApp: boolean;
|
51
49
|
public readonly isReplay = this.manager.isReplay;
|
52
|
-
|
50
|
+
public whiteBoardView?: WhiteBoardView;
|
51
|
+
public _viewWrapper?: HTMLElement;
|
53
52
|
|
54
53
|
constructor(
|
55
54
|
private manager: AppManager,
|
56
|
-
private boxManager: BoxManager,
|
57
55
|
public appId: string,
|
58
56
|
private appProxy: AppProxy,
|
59
57
|
private appOptions?: TAppOptions | (() => TAppOptions)
|
@@ -62,9 +60,13 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
62
60
|
this.isAddApp = appProxy.isAddApp;
|
63
61
|
}
|
64
62
|
|
65
|
-
public get displayer(){
|
63
|
+
public get displayer() {
|
66
64
|
return this.manager.displayer;
|
67
|
-
}
|
65
|
+
}
|
66
|
+
|
67
|
+
public get destroyed() {
|
68
|
+
return this.appProxy.status === "destroyed";
|
69
|
+
}
|
68
70
|
|
69
71
|
/** @deprecated Use context.storage.state instead. */
|
70
72
|
public getAttributes = (): TAttributes | undefined => {
|
@@ -92,13 +94,25 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
92
94
|
if (!view) {
|
93
95
|
view = this.appProxy.createAppDir();
|
94
96
|
}
|
95
|
-
|
96
|
-
this.
|
97
|
-
|
97
|
+
const viewWrapper = document.createElement("div");
|
98
|
+
this._viewWrapper = viewWrapper;
|
99
|
+
viewWrapper.className = "window-manager-view-wrapper";
|
100
|
+
this.box.$content.parentElement?.appendChild(viewWrapper);
|
101
|
+
view.divElement = viewWrapper;
|
102
|
+
this.appProxy.fireMemberStateChange();
|
103
|
+
if (this.isAddApp) {
|
104
|
+
this.ensurePageSize(size);
|
105
|
+
}
|
106
|
+
this.whiteBoardView = new WhiteBoardView(view, this, this.appProxy, this.ensurePageSize);
|
107
|
+
this.appProxy.sideEffectManager.add(() => {
|
108
|
+
return () => {
|
109
|
+
this.whiteBoardView = undefined;
|
110
|
+
}
|
111
|
+
});
|
98
112
|
return this.whiteBoardView;
|
99
113
|
}
|
100
114
|
|
101
|
-
private
|
115
|
+
private ensurePageSize = (size?: number) => {
|
102
116
|
if (!isNumber(size)) return;
|
103
117
|
if (!this.appProxy.scenePath) return;
|
104
118
|
if (this.appProxy.pageState.length >= size) return;
|
@@ -106,25 +120,22 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
106
120
|
throw Error(`[WindowManager]: size ${size} muse be in range [1, ${MAX_PAGE_SIZE}]`);
|
107
121
|
}
|
108
122
|
const needInsert = size - this.appProxy.pageState.length;
|
109
|
-
const
|
110
|
-
|
111
|
-
return { name: `${startPageNumber + index + 1}` };
|
112
|
-
});
|
113
|
-
putScenes(this.room, this.appProxy.scenePath, scenes);
|
123
|
+
const scenes = new Array(needInsert).fill({});
|
124
|
+
this.room?.putScenes(this.appProxy.scenePath, scenes);
|
114
125
|
}
|
115
126
|
|
116
127
|
public getInitScenePath = () => {
|
117
|
-
return this.
|
128
|
+
return this.appProxy.scenePath;
|
118
129
|
};
|
119
130
|
|
120
131
|
/** Get App writable status. */
|
121
132
|
public get isWritable(): boolean {
|
122
|
-
return this.manager.canOperate;
|
133
|
+
return this.manager.canOperate && !this.destroyed;
|
123
134
|
};
|
124
135
|
|
125
136
|
/** Get the App Window UI box. */
|
126
137
|
public get box(): ReadonlyTeleBox {
|
127
|
-
const box = this.
|
138
|
+
const box = this.appProxy.box$.value;
|
128
139
|
if (box) {
|
129
140
|
return box;
|
130
141
|
} else {
|
package/src/App/AppProxy.ts
CHANGED
@@ -3,12 +3,18 @@ import { AppAttributes, AppEvents, Events, SETUP_APP_DELAY } from "../constants"
|
|
3
3
|
import { AppContext } from "./AppContext";
|
4
4
|
import { AppPageStateImpl } from "./AppPageStateImpl";
|
5
5
|
import { appRegister } from "../Register";
|
6
|
-
import {
|
6
|
+
import { ViewSync } from "../View/ViewSync"
|
7
|
+
import { autorun, reaction, toJS } from "white-web-sdk";
|
8
|
+
import { boxEmitter } from "../BoxEmitter";
|
7
9
|
import { BoxManagerNotFoundError } from "../Utils/error";
|
8
|
-
import {
|
10
|
+
import { calculateNextIndex } from "../Page";
|
11
|
+
import { combine, Val, ValManager } from "value-enhancer";
|
12
|
+
import { debounce, get, isEqual } from "lodash";
|
9
13
|
import { emitter } from "../InternalEmitter";
|
10
14
|
import { Fields } from "../AttributesDelegate";
|
11
15
|
import { log } from "../Utils/log";
|
16
|
+
import { SideEffectManager } from "side-effect-manager";
|
17
|
+
import type { ICamera, ISize } from "../AttributesDelegate";
|
12
18
|
import {
|
13
19
|
entireScenes,
|
14
20
|
getScenePath,
|
@@ -24,14 +30,12 @@ import type {
|
|
24
30
|
setAppOptions,
|
25
31
|
AppListenerKeys,
|
26
32
|
} from "../index";
|
27
|
-
import type { SceneState, View, SceneDefinition
|
33
|
+
import type { SceneState, View, SceneDefinition, MemberState} from "white-web-sdk";
|
28
34
|
import type { AppManager } from "../AppManager";
|
29
35
|
import type { NetlessApp } from "../typings";
|
30
|
-
import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
36
|
+
import type { ReadonlyTeleBox, TeleBoxRect } from "@netless/telebox-insider";
|
31
37
|
import type { PageRemoveService, PageState } from "../Page";
|
32
|
-
import {
|
33
|
-
import { boxEmitter } from "../BoxEmitter";
|
34
|
-
import { SideEffectManager } from "side-effect-manager";
|
38
|
+
import { createValSync } from "../Utils/Reactive";
|
35
39
|
|
36
40
|
export type AppEmitter = Emittery<AppEmitterEvent>;
|
37
41
|
|
@@ -48,17 +52,26 @@ export class AppProxy implements PageRemoveService {
|
|
48
52
|
private appProxies = this.manager.appProxies;
|
49
53
|
private viewManager = this.manager.viewManager;
|
50
54
|
private store = this.manager.store;
|
55
|
+
public uid = this.manager.uid;
|
51
56
|
|
52
57
|
public isAddApp: boolean;
|
53
|
-
|
58
|
+
public status: "normal" | "destroyed" = "normal";
|
54
59
|
private stateKey: string;
|
55
60
|
public _pageState: AppPageStateImpl;
|
56
|
-
private _prevFullPath: string | undefined;
|
57
61
|
|
58
|
-
public appResult?: NetlessApp
|
59
|
-
public appContext?: AppContext
|
62
|
+
public appResult?: NetlessApp;
|
63
|
+
public appContext?: AppContext;
|
64
|
+
|
65
|
+
public sideEffectManager = new SideEffectManager();
|
66
|
+
private valManager = new ValManager();
|
60
67
|
|
61
|
-
private
|
68
|
+
private fullPath$ = this.valManager.attach(new Val<string | undefined>(undefined));
|
69
|
+
private viewSync?: ViewSync;
|
70
|
+
|
71
|
+
public camera$ = this.valManager.attach(new Val<ICamera | undefined>(undefined));
|
72
|
+
public size$ = this.valManager.attach(new Val<ISize | undefined>(undefined));
|
73
|
+
public box$ = this.valManager.attach(new Val<ReadonlyTeleBox | undefined>(undefined));
|
74
|
+
public view$ = this.valManager.attach(new Val<View | undefined>(undefined));
|
62
75
|
|
63
76
|
constructor(
|
64
77
|
private params: BaseInsertParams,
|
@@ -90,16 +103,142 @@ export class AppProxy implements PageRemoveService {
|
|
90
103
|
view: this.view,
|
91
104
|
notifyPageStateChange: this.notifyPageStateChange,
|
92
105
|
});
|
93
|
-
this.sideEffectManager.add(() =>
|
94
|
-
|
95
|
-
|
96
|
-
this.sideEffectManager.add(() => {
|
97
|
-
return emitter.on("roomMembersChange", members => {
|
106
|
+
this.sideEffectManager.add(() => () => this._pageState.destroy());
|
107
|
+
this.sideEffectManager.add(() =>
|
108
|
+
emitter.on("roomMembersChange", members => {
|
98
109
|
this.appEmitter.emit("roomMembersChange", members);
|
99
|
-
})
|
110
|
+
})
|
111
|
+
);
|
112
|
+
this.camera$.setValue(toJS(this.appAttributes.camera));
|
113
|
+
this.size$.setValue(toJS(this.appAttributes.size));
|
114
|
+
this.addCameraReaction();
|
115
|
+
this.addSizeReaction();
|
116
|
+
this.sideEffectManager.add(() =>
|
117
|
+
combine([this.box$, this.view$]).subscribe(([box, view]) => {
|
118
|
+
if (box && view) {
|
119
|
+
if (!this.camera$.value) {
|
120
|
+
this.storeCamera({
|
121
|
+
centerX: null,
|
122
|
+
centerY: null,
|
123
|
+
scale: 1,
|
124
|
+
id: this.uid,
|
125
|
+
});
|
126
|
+
this.camera$.setValue(toJS(this.appAttributes.camera));
|
127
|
+
}
|
128
|
+
if (!this.size$.value && box.contentStageRect) {
|
129
|
+
const initialRect = this.computedInitialRect(box.contentStageRect);
|
130
|
+
const width = initialRect?.width || box.contentStageRect.width;
|
131
|
+
const height = initialRect?.height || box.contentStageRect.height;
|
132
|
+
this.storeSize({
|
133
|
+
id: this.uid,
|
134
|
+
width,
|
135
|
+
height,
|
136
|
+
});
|
137
|
+
this.size$.setValue(toJS(this.appAttributes.size));
|
138
|
+
}
|
139
|
+
this.viewSync = new ViewSync({
|
140
|
+
uid: this.uid,
|
141
|
+
view$: this.view$,
|
142
|
+
camera$: this.camera$,
|
143
|
+
size$: this.size$,
|
144
|
+
stageRect$: box._contentStageRect$,
|
145
|
+
storeCamera: this.storeCamera,
|
146
|
+
storeSize: this.storeSize
|
147
|
+
});
|
148
|
+
this.sideEffectManager.add(() => () => this.viewSync?.destroy());
|
149
|
+
}
|
150
|
+
})
|
151
|
+
);
|
152
|
+
this.sideEffectManager.add(() =>
|
153
|
+
emitter.on("memberStateChange", this.onMemberStateChange)
|
154
|
+
);
|
155
|
+
this.box$.subscribe(box => {
|
156
|
+
if (!box) return;
|
157
|
+
this.sideEffectManager.add(() => [
|
158
|
+
createValSync(
|
159
|
+
() => this.appAttributes?.state.visible,
|
160
|
+
box._visible$,
|
161
|
+
this.isAddApp,
|
162
|
+
),
|
163
|
+
createValSync(
|
164
|
+
() => this.appAttributes?.state.ratio,
|
165
|
+
box._ratio$,
|
166
|
+
this.isAddApp,
|
167
|
+
),
|
168
|
+
createValSync(
|
169
|
+
() => this.appAttributes?.state.stageRatio,
|
170
|
+
box._stageRatio$,
|
171
|
+
this.isAddApp,
|
172
|
+
),
|
173
|
+
createValSync(
|
174
|
+
() => this.appAttributes?.state.draggable,
|
175
|
+
box._draggable$,
|
176
|
+
this.isAddApp,
|
177
|
+
),
|
178
|
+
createValSync(
|
179
|
+
() => this.appAttributes?.state.resizable,
|
180
|
+
box._resizable$,
|
181
|
+
this.isAddApp,
|
182
|
+
),
|
183
|
+
box._visible$.subscribe(visible => {
|
184
|
+
this.store.updateAppState(this.id, AppAttributes.Visible, visible);
|
185
|
+
}),
|
186
|
+
box._ratio$.subscribe(ratio => {
|
187
|
+
this.store.updateAppState(this.id, AppAttributes.Ratio, ratio);
|
188
|
+
}),
|
189
|
+
box._stageRatio$.subscribe(stageRatio => {
|
190
|
+
this.store.updateAppState(this.id, AppAttributes.StageRatio, stageRatio);
|
191
|
+
}),
|
192
|
+
box._draggable$.subscribe(draggable => {
|
193
|
+
this.store.updateAppState(this.id, AppAttributes.Draggable, draggable);
|
194
|
+
}),
|
195
|
+
box._resizable$.subscribe(resizable => {
|
196
|
+
console.log("resizable change", resizable);
|
197
|
+
this.store.updateAppState(this.id, AppAttributes.Resizable, resizable);
|
198
|
+
}),
|
199
|
+
])
|
100
200
|
});
|
101
201
|
}
|
102
202
|
|
203
|
+
public fireMemberStateChange = () => {
|
204
|
+
if (this.manager.room) {
|
205
|
+
this.onMemberStateChange(this.manager.room.state.memberState);
|
206
|
+
}
|
207
|
+
}
|
208
|
+
|
209
|
+
private onMemberStateChange = (memberState: MemberState) => {
|
210
|
+
// clicker 教具把事件穿透给下层
|
211
|
+
const needPointerEventsNone = memberState.currentApplianceName === "clicker";
|
212
|
+
if (needPointerEventsNone) {
|
213
|
+
if (this.appContext?._viewWrapper) {
|
214
|
+
this.appContext._viewWrapper.style.pointerEvents = "none";
|
215
|
+
}
|
216
|
+
} else {
|
217
|
+
if (this.appContext?._viewWrapper) {
|
218
|
+
this.appContext._viewWrapper.style.pointerEvents = "auto";
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
private computedInitialRect = (boxRect: TeleBoxRect) => {
|
224
|
+
const managerRect = this.manager.boxManager?.stageRect;
|
225
|
+
if (managerRect) {
|
226
|
+
const { width, height } = managerRect;
|
227
|
+
const boxRatio = boxRect.height / boxRect.width;
|
228
|
+
if (height < 480) {
|
229
|
+
return {
|
230
|
+
width: 480 / boxRatio,
|
231
|
+
height: 480,
|
232
|
+
};
|
233
|
+
} else {
|
234
|
+
return {
|
235
|
+
width: width * 0.65,
|
236
|
+
height: height * 0.65,
|
237
|
+
};
|
238
|
+
}
|
239
|
+
}
|
240
|
+
}
|
241
|
+
|
103
242
|
public createAppDir() {
|
104
243
|
const scenePath = this.scenePath || this.appScenePath;
|
105
244
|
const sceneNode = this._pageState.createSceneNode(scenePath);
|
@@ -127,7 +266,7 @@ export class AppProxy implements PageRemoveService {
|
|
127
266
|
}
|
128
267
|
|
129
268
|
public get view(): View | undefined {
|
130
|
-
return this.
|
269
|
+
return this.view$.value;
|
131
270
|
}
|
132
271
|
|
133
272
|
public get viewIndex(): number | undefined {
|
@@ -162,7 +301,7 @@ export class AppProxy implements PageRemoveService {
|
|
162
301
|
}
|
163
302
|
|
164
303
|
public setFullPath(path: string) {
|
165
|
-
this.
|
304
|
+
this.store.updateAppAttributes(this.id, Fields.FullPath, path);
|
166
305
|
}
|
167
306
|
|
168
307
|
public async baseInsertApp(skipUpdate = false): Promise<{ appId: string; app: NetlessApp }> {
|
@@ -191,7 +330,7 @@ export class AppProxy implements PageRemoveService {
|
|
191
330
|
}
|
192
331
|
|
193
332
|
public get box(): ReadonlyTeleBox | undefined {
|
194
|
-
return this.
|
333
|
+
return this.box$.value;
|
195
334
|
}
|
196
335
|
|
197
336
|
private async setupApp(
|
@@ -205,7 +344,7 @@ export class AppProxy implements PageRemoveService {
|
|
205
344
|
if (!this.boxManager) {
|
206
345
|
throw new BoxManagerNotFoundError();
|
207
346
|
}
|
208
|
-
const context = new AppContext(this.manager,
|
347
|
+
const context = new AppContext(this.manager, appId, this, appOptions);
|
209
348
|
this.appContext = context;
|
210
349
|
try {
|
211
350
|
emitter.once(`${appId}${Events.WindowCreated}` as any).then(async () => {
|
@@ -225,13 +364,14 @@ export class AppProxy implements PageRemoveService {
|
|
225
364
|
this.fixMobileSize();
|
226
365
|
}, SETUP_APP_DELAY);
|
227
366
|
});
|
228
|
-
this.boxManager?.createBox({
|
367
|
+
const box = this.boxManager?.createBox({
|
229
368
|
appId: appId,
|
230
369
|
app,
|
231
370
|
options,
|
232
371
|
canOperate: this.manager.canOperate,
|
233
372
|
smartPosition: this.isAddApp,
|
234
373
|
});
|
374
|
+
this.box$.setValue(box);
|
235
375
|
if (this.isAddApp && this.box) {
|
236
376
|
this.store.updateAppState(appId, AppAttributes.ZIndex, this.box.zIndex);
|
237
377
|
this.boxManager.focusBox({ appId }, false);
|
@@ -246,12 +386,14 @@ export class AppProxy implements PageRemoveService {
|
|
246
386
|
private fixMobileSize() {
|
247
387
|
const box = this.boxManager?.getBox(this.id);
|
248
388
|
if (box) {
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
389
|
+
if (!box.minimized) {
|
390
|
+
this.boxManager?.resizeBox({
|
391
|
+
appId: this.id,
|
392
|
+
width: box.intrinsicWidth + 0.001,
|
393
|
+
height: box.intrinsicHeight + 0.001,
|
394
|
+
skipUpdate: true,
|
395
|
+
});
|
396
|
+
}
|
255
397
|
}
|
256
398
|
}
|
257
399
|
|
@@ -376,7 +518,7 @@ export class AppProxy implements PageRemoveService {
|
|
376
518
|
}
|
377
519
|
|
378
520
|
private appAttributesUpdateListener = (appId: string) => {
|
379
|
-
this.manager.refresher
|
521
|
+
this.manager.refresher.add(appId, () => {
|
380
522
|
return autorun(() => {
|
381
523
|
const attrs = this.manager.attributes[appId];
|
382
524
|
if (attrs) {
|
@@ -384,7 +526,7 @@ export class AppProxy implements PageRemoveService {
|
|
384
526
|
}
|
385
527
|
});
|
386
528
|
});
|
387
|
-
this.manager.refresher
|
529
|
+
this.manager.refresher.add(this.stateKey, () => {
|
388
530
|
return autorun(() => {
|
389
531
|
const appState = this.appAttributes?.state;
|
390
532
|
if (appState?.zIndex > 0 && appState.zIndex !== this.box?.zIndex) {
|
@@ -392,13 +534,13 @@ export class AppProxy implements PageRemoveService {
|
|
392
534
|
}
|
393
535
|
});
|
394
536
|
});
|
395
|
-
this.manager.refresher
|
537
|
+
this.manager.refresher.add(`${appId}-fullPath`, () => {
|
396
538
|
return autorun(() => {
|
397
539
|
const fullPath = this.appAttributes?.fullPath;
|
398
540
|
this.setFocusScenePathHandler(fullPath);
|
399
|
-
if (this.
|
541
|
+
if (this.fullPath$.value !== fullPath) {
|
400
542
|
this.notifyPageStateChange();
|
401
|
-
this.
|
543
|
+
this.fullPath$.setValue(fullPath);
|
402
544
|
}
|
403
545
|
});
|
404
546
|
});
|
@@ -428,6 +570,7 @@ export class AppProxy implements PageRemoveService {
|
|
428
570
|
|
429
571
|
private createView(): View {
|
430
572
|
const view = this.viewManager.createView(this.id);
|
573
|
+
this.view$.setValue(view);
|
431
574
|
this.setViewFocusScenePath();
|
432
575
|
return view;
|
433
576
|
}
|
@@ -477,10 +620,37 @@ export class AppProxy implements PageRemoveService {
|
|
477
620
|
const fullPath = this._pageState.getFullPath(index);
|
478
621
|
if (fullPath) {
|
479
622
|
this.setFullPath(fullPath);
|
623
|
+
setScenePath(this.manager.room, fullPath);
|
480
624
|
}
|
481
625
|
}
|
482
626
|
}
|
483
627
|
|
628
|
+
public storeCamera = (camera: ICamera) => {
|
629
|
+
this.store.updateAppAttributes(this.id, Fields.Camera, camera);
|
630
|
+
};
|
631
|
+
|
632
|
+
public storeSize = (size: ISize) => {
|
633
|
+
this.store.updateAppAttributes(this.id, Fields.Size, size);
|
634
|
+
};
|
635
|
+
|
636
|
+
public updateSize = (width: number, height: number) => {
|
637
|
+
const iSize = {
|
638
|
+
id: this.manager.uid,
|
639
|
+
width, height
|
640
|
+
}
|
641
|
+
this.store.updateAppAttributes(this.id, Fields.Size, iSize);
|
642
|
+
this.size$.setValue(iSize);
|
643
|
+
}
|
644
|
+
|
645
|
+
public moveCamera = (camera: Partial<ICamera>) => {
|
646
|
+
if (!this.camera$.value) {
|
647
|
+
return;
|
648
|
+
}
|
649
|
+
const nextCamera = { ...this.camera$.value, ...camera, id: this.uid };
|
650
|
+
this.storeCamera(nextCamera);
|
651
|
+
this.camera$.setValue(nextCamera);
|
652
|
+
};
|
653
|
+
|
484
654
|
public async destroy(
|
485
655
|
needCloseBox: boolean,
|
486
656
|
cleanAttrs: boolean,
|
@@ -496,6 +666,7 @@ export class AppProxy implements PageRemoveService {
|
|
496
666
|
console.error("[WindowManager]: notifyApp error", error.message, error.stack);
|
497
667
|
}
|
498
668
|
this.appEmitter.clearListeners();
|
669
|
+
this.sideEffectManager.flushAll();
|
499
670
|
emitter.emit(`destroy-${this.id}` as any, { error });
|
500
671
|
if (needCloseBox) {
|
501
672
|
this.boxManager?.closeBox(this.id, skipUpdate);
|
@@ -510,11 +681,52 @@ export class AppProxy implements PageRemoveService {
|
|
510
681
|
|
511
682
|
this.viewManager.destroyView(this.id);
|
512
683
|
this.manager.appStatus.delete(this.id);
|
513
|
-
this.manager.refresher
|
514
|
-
this.manager.refresher
|
515
|
-
this.manager.refresher
|
516
|
-
this.
|
517
|
-
this.
|
684
|
+
this.manager.refresher.remove(this.id);
|
685
|
+
this.manager.refresher.remove(this.stateKey);
|
686
|
+
this.manager.refresher.remove(`${this.id}-fullPath`);
|
687
|
+
this.manager.refresher.remove(`${this.id}-camera`);
|
688
|
+
this.manager.refresher.remove(`${this.id}-size`);
|
689
|
+
this.valManager.destroy();
|
690
|
+
}
|
691
|
+
|
692
|
+
private addCameraReaction = () => {
|
693
|
+
this.sideEffectManager.add(() =>
|
694
|
+
this.manager.refresher.add(`${this.id}-camera`, () =>
|
695
|
+
reaction(
|
696
|
+
() => this.appAttributes?.camera,
|
697
|
+
camera => {
|
698
|
+
if (camera) {
|
699
|
+
const rawCamera = toJS(camera);
|
700
|
+
if (!isEqual(rawCamera, this.camera$.value)) {
|
701
|
+
this.camera$.setValue(rawCamera);
|
702
|
+
}
|
703
|
+
}
|
704
|
+
}
|
705
|
+
)
|
706
|
+
)
|
707
|
+
, "camera");
|
708
|
+
}
|
709
|
+
|
710
|
+
private addSizeReaction = () => {
|
711
|
+
this.sideEffectManager.add(() =>
|
712
|
+
this.manager.refresher.add(`${this.id}-size`, () =>
|
713
|
+
reaction(
|
714
|
+
() => this.appAttributes?.size,
|
715
|
+
size => {
|
716
|
+
if (size) {
|
717
|
+
const rawSize = toJS(size);
|
718
|
+
if (!isEqual(rawSize, this.size$.value)) {
|
719
|
+
this.size$.setValue(rawSize);
|
720
|
+
}
|
721
|
+
}
|
722
|
+
}
|
723
|
+
)
|
724
|
+
)
|
725
|
+
, "size");
|
726
|
+
}
|
727
|
+
|
728
|
+
public onFocus = () => {
|
729
|
+
this.setScenePath();
|
518
730
|
}
|
519
731
|
|
520
732
|
public close(): Promise<void> {
|
@@ -1,26 +1,56 @@
|
|
1
1
|
import { putScenes } from "../Utils/Common";
|
2
2
|
import { Val } from "value-enhancer";
|
3
|
+
import { pick } from "lodash";
|
3
4
|
|
4
5
|
import type { ReadonlyVal } from "value-enhancer";
|
5
6
|
import type { AddPageParams, PageController, PageState } from "../Page";
|
6
7
|
import type { AppProxy } from "./AppProxy";
|
7
8
|
import type { AppContext } from "./AppContext";
|
9
|
+
import type { View } from "white-web-sdk";
|
10
|
+
import type { TeleBoxRect } from "@netless/telebox-insider";
|
11
|
+
import type { ICamera } from "../AttributesDelegate";
|
12
|
+
|
13
|
+
export type WhiteBoardViewCamera = Omit<ICamera, "scale" | "id">;
|
8
14
|
|
9
15
|
export class WhiteBoardView implements PageController {
|
10
16
|
public readonly pageState$: ReadonlyVal<PageState>;
|
17
|
+
public readonly camera$: ReadonlyVal<WhiteBoardViewCamera>;
|
11
18
|
|
12
|
-
constructor(
|
19
|
+
constructor(
|
20
|
+
public view: View,
|
21
|
+
protected appContext: AppContext,
|
22
|
+
protected appProxy: AppProxy,
|
23
|
+
public ensureSize: (size: number) => void
|
24
|
+
) {
|
13
25
|
const pageState$ = new Val<PageState>(appProxy.pageState);
|
14
26
|
this.pageState$ = pageState$;
|
15
|
-
appProxy.
|
16
|
-
|
17
|
-
|
27
|
+
this.appProxy.sideEffectManager.add(() =>
|
28
|
+
appProxy.appEmitter.on("pageStateChange", pageState => {
|
29
|
+
pageState$.setValue(pageState);
|
30
|
+
})
|
31
|
+
);
|
32
|
+
const camera$ = new Val<WhiteBoardViewCamera>(
|
33
|
+
pick(this.view.camera, ["centerX", "centerY"])
|
34
|
+
);
|
35
|
+
this.camera$ = camera$;
|
36
|
+
this.appProxy.sideEffectManager.add(() =>
|
37
|
+
appProxy.camera$.subscribe(camera => {
|
38
|
+
if (camera) {
|
39
|
+
camera$.setValue(pick(camera, ["centerX", "centerY"]));
|
40
|
+
}
|
41
|
+
})
|
42
|
+
);
|
43
|
+
view.disableCameraTransform = true;
|
18
44
|
}
|
19
45
|
|
20
46
|
public get pageState() {
|
21
47
|
return this.pageState$.value;
|
22
48
|
}
|
23
49
|
|
50
|
+
public moveCamera(camera: Partial<WhiteBoardViewCamera>) {
|
51
|
+
this.appProxy.moveCamera(camera);
|
52
|
+
}
|
53
|
+
|
24
54
|
public nextPage = async (): Promise<boolean> => {
|
25
55
|
const nextIndex = this.pageState.index + 1;
|
26
56
|
return this.jumpPage(nextIndex);
|
@@ -65,4 +95,8 @@ export class WhiteBoardView implements PageController {
|
|
65
95
|
}
|
66
96
|
return this.appProxy.removeSceneByIndex(needRemoveIndex);
|
67
97
|
};
|
98
|
+
|
99
|
+
public setRect(rect: Omit<TeleBoxRect, "x" | "y">) {
|
100
|
+
this.appProxy.updateSize(rect.width, rect.height);
|
101
|
+
}
|
68
102
|
}
|
package/src/App/index.ts
CHANGED