@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/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,11 +25,15 @@ 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 {
|
33
|
-
|
31
|
+
import { isBoolean, isNumber } from "lodash";
|
32
|
+
|
33
|
+
export type CreateWhiteBoardViewParams = {
|
34
|
+
size?: number;
|
35
|
+
syncCamera?: boolean;
|
36
|
+
}
|
34
37
|
|
35
38
|
export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOptions = any> {
|
36
39
|
public readonly emitter: Emittery<AppEmitterEvent<TAttributes>>;
|
@@ -49,11 +52,11 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
49
52
|
private store = this.manager.store;
|
50
53
|
public readonly isAddApp: boolean;
|
51
54
|
public readonly isReplay = this.manager.isReplay;
|
52
|
-
|
55
|
+
public whiteBoardView?: WhiteBoardView;
|
56
|
+
public _viewWrapper?: HTMLElement;
|
53
57
|
|
54
58
|
constructor(
|
55
59
|
private manager: AppManager,
|
56
|
-
private boxManager: BoxManager,
|
57
60
|
public appId: string,
|
58
61
|
private appProxy: AppProxy,
|
59
62
|
private appOptions?: TAppOptions | (() => TAppOptions)
|
@@ -62,9 +65,13 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
62
65
|
this.isAddApp = appProxy.isAddApp;
|
63
66
|
}
|
64
67
|
|
65
|
-
public get displayer(){
|
68
|
+
public get displayer() {
|
66
69
|
return this.manager.displayer;
|
67
|
-
}
|
70
|
+
}
|
71
|
+
|
72
|
+
public get destroyed() {
|
73
|
+
return this.appProxy.status === "destroyed";
|
74
|
+
}
|
68
75
|
|
69
76
|
/** @deprecated Use context.storage.state instead. */
|
70
77
|
public getAttributes = (): TAttributes | undefined => {
|
@@ -84,7 +91,7 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
84
91
|
return this.appProxy.view;
|
85
92
|
};
|
86
93
|
|
87
|
-
public createWhiteBoardView = (
|
94
|
+
public createWhiteBoardView = (params?: CreateWhiteBoardViewParams): WhiteBoardView => {
|
88
95
|
if (this.whiteBoardView) {
|
89
96
|
return this.whiteBoardView;
|
90
97
|
}
|
@@ -92,13 +99,31 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
92
99
|
if (!view) {
|
93
100
|
view = this.appProxy.createAppDir();
|
94
101
|
}
|
95
|
-
|
96
|
-
|
97
|
-
|
102
|
+
if (params) {
|
103
|
+
if (isBoolean(params.syncCamera)) {
|
104
|
+
this.appProxy.syncCamera$.setValue(params.syncCamera);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
const viewWrapper = document.createElement("div");
|
108
|
+
this._viewWrapper = viewWrapper;
|
109
|
+
viewWrapper.className = "window-manager-view-wrapper";
|
110
|
+
this.box.$content.parentElement?.appendChild(viewWrapper);
|
111
|
+
view.divElement = viewWrapper;
|
112
|
+
this.appProxy.fireMemberStateChange();
|
113
|
+
if (this.isAddApp) {
|
114
|
+
this.ensurePageSize(params?.size);
|
115
|
+
}
|
116
|
+
this.whiteBoardView = new WhiteBoardView(view, this, this.appProxy, this.ensurePageSize);
|
117
|
+
this.appProxy.sideEffectManager.add(() => {
|
118
|
+
return () => {
|
119
|
+
this.whiteBoardView = undefined;
|
120
|
+
}
|
121
|
+
});
|
122
|
+
this.appProxy.whiteBoardViewCreated$.setValue(true);
|
98
123
|
return this.whiteBoardView;
|
99
124
|
}
|
100
125
|
|
101
|
-
private
|
126
|
+
private ensurePageSize = (size?: number) => {
|
102
127
|
if (!isNumber(size)) return;
|
103
128
|
if (!this.appProxy.scenePath) return;
|
104
129
|
if (this.appProxy.pageState.length >= size) return;
|
@@ -106,25 +131,22 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
106
131
|
throw Error(`[WindowManager]: size ${size} muse be in range [1, ${MAX_PAGE_SIZE}]`);
|
107
132
|
}
|
108
133
|
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);
|
134
|
+
const scenes = new Array(needInsert).fill({});
|
135
|
+
this.room?.putScenes(this.appProxy.scenePath, scenes);
|
114
136
|
}
|
115
137
|
|
116
138
|
public getInitScenePath = () => {
|
117
|
-
return this.
|
139
|
+
return this.appProxy.scenePath;
|
118
140
|
};
|
119
141
|
|
120
142
|
/** Get App writable status. */
|
121
143
|
public get isWritable(): boolean {
|
122
|
-
return this.manager.canOperate;
|
144
|
+
return this.manager.canOperate && !this.destroyed;
|
123
145
|
};
|
124
146
|
|
125
147
|
/** Get the App Window UI box. */
|
126
148
|
public get box(): ReadonlyTeleBox {
|
127
|
-
const box = this.
|
149
|
+
const box = this.appProxy.box$.value;
|
128
150
|
if (box) {
|
129
151
|
return box;
|
130
152
|
} 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, isUndefined, omitBy } 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,
|
@@ -19,19 +25,16 @@ import {
|
|
19
25
|
} from "../Utils/Common";
|
20
26
|
import type {
|
21
27
|
AppEmitterEvent,
|
22
|
-
AppInitState,
|
23
28
|
BaseInsertParams,
|
24
29
|
setAppOptions,
|
25
30
|
AppListenerKeys,
|
26
31
|
} from "../index";
|
27
|
-
import type { SceneState, View, SceneDefinition
|
32
|
+
import type { SceneState, View, SceneDefinition, MemberState} from "white-web-sdk";
|
28
33
|
import type { AppManager } from "../AppManager";
|
29
34
|
import type { NetlessApp } from "../typings";
|
30
|
-
import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
35
|
+
import type { ReadonlyTeleBox, TeleBoxRect } from "@netless/telebox-insider";
|
31
36
|
import type { PageRemoveService, PageState } from "../Page";
|
32
|
-
import {
|
33
|
-
import { boxEmitter } from "../BoxEmitter";
|
34
|
-
import { SideEffectManager } from "side-effect-manager";
|
37
|
+
import type { AppState } from "./type";
|
35
38
|
|
36
39
|
export type AppEmitter = Emittery<AppEmitterEvent>;
|
37
40
|
|
@@ -48,17 +51,28 @@ export class AppProxy implements PageRemoveService {
|
|
48
51
|
private appProxies = this.manager.appProxies;
|
49
52
|
private viewManager = this.manager.viewManager;
|
50
53
|
private store = this.manager.store;
|
54
|
+
public uid = this.manager.uid;
|
51
55
|
|
52
56
|
public isAddApp: boolean;
|
53
|
-
|
57
|
+
public status: "normal" | "destroyed" = "normal";
|
54
58
|
private stateKey: string;
|
55
59
|
public _pageState: AppPageStateImpl;
|
56
|
-
private _prevFullPath: string | undefined;
|
57
60
|
|
58
|
-
public appResult?: NetlessApp
|
59
|
-
public appContext?: AppContext
|
61
|
+
public appResult?: NetlessApp;
|
62
|
+
public appContext?: AppContext;
|
63
|
+
|
64
|
+
public sideEffectManager = new SideEffectManager();
|
65
|
+
private valManager = new ValManager();
|
60
66
|
|
61
|
-
private
|
67
|
+
private fullPath$ = this.valManager.attach(new Val<string | undefined>(undefined));
|
68
|
+
private viewSync?: ViewSync;
|
69
|
+
|
70
|
+
public camera$ = this.valManager.attach(new Val<ICamera | undefined>(undefined));
|
71
|
+
public size$ = this.valManager.attach(new Val<ISize | undefined>(undefined));
|
72
|
+
public box$ = this.valManager.attach(new Val<ReadonlyTeleBox | undefined>(undefined));
|
73
|
+
public view$ = this.valManager.attach(new Val<View | undefined>(undefined));
|
74
|
+
public syncCamera$ = this.valManager.attach(new Val<boolean>(true));
|
75
|
+
public whiteBoardViewCreated$ = this.valManager.attach(new Val<boolean>(false));
|
62
76
|
|
63
77
|
constructor(
|
64
78
|
private params: BaseInsertParams,
|
@@ -90,14 +104,110 @@ export class AppProxy implements PageRemoveService {
|
|
90
104
|
view: this.view,
|
91
105
|
notifyPageStateChange: this.notifyPageStateChange,
|
92
106
|
});
|
93
|
-
this.sideEffectManager.add(() =>
|
94
|
-
|
95
|
-
|
96
|
-
this.sideEffectManager.add(() => {
|
97
|
-
return emitter.on("roomMembersChange", members => {
|
107
|
+
this.sideEffectManager.add(() => () => this._pageState.destroy());
|
108
|
+
this.sideEffectManager.add(() =>
|
109
|
+
emitter.on("roomMembersChange", members => {
|
98
110
|
this.appEmitter.emit("roomMembersChange", members);
|
99
|
-
})
|
100
|
-
|
111
|
+
})
|
112
|
+
);
|
113
|
+
this.camera$.setValue(toJS(this.appAttributes.camera));
|
114
|
+
this.size$.setValue(toJS(this.appAttributes.size));
|
115
|
+
this.addCameraReaction();
|
116
|
+
this.addSizeReaction();
|
117
|
+
this.sideEffectManager.add(() =>
|
118
|
+
emitter.on("memberStateChange", this.onMemberStateChange)
|
119
|
+
);
|
120
|
+
this.sideEffectManager.add(() => [
|
121
|
+
this.syncCamera$.reaction(syncCamera => {
|
122
|
+
if (!syncCamera) {
|
123
|
+
if (this.viewSync) {
|
124
|
+
this.viewSync.destroy();
|
125
|
+
this.viewSync = undefined;
|
126
|
+
this.sideEffectManager.flush("camera");
|
127
|
+
this.sideEffectManager.flush("size");
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}),
|
131
|
+
this.whiteBoardViewCreated$.reaction(created => {
|
132
|
+
if (created && this.box) {
|
133
|
+
if (!this.syncCamera$.value) return;
|
134
|
+
combine([this.box$, this.view$]).subscribe(([box, view]) => {
|
135
|
+
if (box && view) {
|
136
|
+
if (!this.camera$.value) {
|
137
|
+
this.storeCamera({
|
138
|
+
centerX: null,
|
139
|
+
centerY: null,
|
140
|
+
scale: 1,
|
141
|
+
id: this.uid,
|
142
|
+
});
|
143
|
+
this.camera$.setValue(toJS(this.appAttributes.camera));
|
144
|
+
}
|
145
|
+
if (!this.size$.value && box.contentStageRect) {
|
146
|
+
const initialRect = this.computedInitialRect(box.contentStageRect);
|
147
|
+
const width = initialRect?.width || box.contentStageRect.width;
|
148
|
+
const height = initialRect?.height || box.contentStageRect.height;
|
149
|
+
this.storeSize({
|
150
|
+
id: this.uid,
|
151
|
+
width,
|
152
|
+
height,
|
153
|
+
});
|
154
|
+
this.size$.setValue(toJS(this.appAttributes.size));
|
155
|
+
}
|
156
|
+
this.viewSync = new ViewSync({
|
157
|
+
uid: this.uid,
|
158
|
+
view$: this.view$,
|
159
|
+
camera$: this.camera$,
|
160
|
+
size$: this.size$,
|
161
|
+
stageRect$: box._contentStageRect$,
|
162
|
+
storeCamera: this.storeCamera,
|
163
|
+
storeSize: this.storeSize
|
164
|
+
});
|
165
|
+
this.sideEffectManager.add(() => () => this.viewSync?.destroy());
|
166
|
+
this.whiteBoardViewCreated$.destroy();
|
167
|
+
}
|
168
|
+
})
|
169
|
+
}
|
170
|
+
})
|
171
|
+
]);
|
172
|
+
}
|
173
|
+
|
174
|
+
public fireMemberStateChange = () => {
|
175
|
+
if (this.manager.room) {
|
176
|
+
this.onMemberStateChange(this.manager.room.state.memberState);
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
private onMemberStateChange = (memberState: MemberState) => {
|
181
|
+
// clicker 教具把事件穿透给下层
|
182
|
+
const needPointerEventsNone = memberState.currentApplianceName === "clicker";
|
183
|
+
if (needPointerEventsNone) {
|
184
|
+
if (this.appContext?._viewWrapper) {
|
185
|
+
this.appContext._viewWrapper.style.pointerEvents = "none";
|
186
|
+
}
|
187
|
+
} else {
|
188
|
+
if (this.appContext?._viewWrapper) {
|
189
|
+
this.appContext._viewWrapper.style.pointerEvents = "auto";
|
190
|
+
}
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
private computedInitialRect = (boxRect: TeleBoxRect) => {
|
195
|
+
const managerRect = this.manager.boxManager?.stageRect;
|
196
|
+
if (managerRect) {
|
197
|
+
const { width, height } = managerRect;
|
198
|
+
const boxRatio = boxRect.height / boxRect.width;
|
199
|
+
if (height < 480) {
|
200
|
+
return {
|
201
|
+
width: 480 / boxRatio,
|
202
|
+
height: 480,
|
203
|
+
};
|
204
|
+
} else {
|
205
|
+
return {
|
206
|
+
width: width * 0.65,
|
207
|
+
height: height * 0.65,
|
208
|
+
};
|
209
|
+
}
|
210
|
+
}
|
101
211
|
}
|
102
212
|
|
103
213
|
public createAppDir() {
|
@@ -127,7 +237,7 @@ export class AppProxy implements PageRemoveService {
|
|
127
237
|
}
|
128
238
|
|
129
239
|
public get view(): View | undefined {
|
130
|
-
return this.
|
240
|
+
return this.view$.value;
|
131
241
|
}
|
132
242
|
|
133
243
|
public get viewIndex(): number | undefined {
|
@@ -162,7 +272,7 @@ export class AppProxy implements PageRemoveService {
|
|
162
272
|
}
|
163
273
|
|
164
274
|
public setFullPath(path: string) {
|
165
|
-
this.
|
275
|
+
this.store.updateAppAttributes(this.id, Fields.FullPath, path);
|
166
276
|
}
|
167
277
|
|
168
278
|
public async baseInsertApp(skipUpdate = false): Promise<{ appId: string; app: NetlessApp }> {
|
@@ -191,7 +301,7 @@ export class AppProxy implements PageRemoveService {
|
|
191
301
|
}
|
192
302
|
|
193
303
|
public get box(): ReadonlyTeleBox | undefined {
|
194
|
-
return this.
|
304
|
+
return this.box$.value;
|
195
305
|
}
|
196
306
|
|
197
307
|
private async setupApp(
|
@@ -205,11 +315,11 @@ export class AppProxy implements PageRemoveService {
|
|
205
315
|
if (!this.boxManager) {
|
206
316
|
throw new BoxManagerNotFoundError();
|
207
317
|
}
|
208
|
-
const context = new AppContext(this.manager,
|
318
|
+
const context = new AppContext(this.manager, appId, this, appOptions);
|
209
319
|
this.appContext = context;
|
210
320
|
try {
|
211
321
|
emitter.once(`${appId}${Events.WindowCreated}` as any).then(async () => {
|
212
|
-
let boxInitState:
|
322
|
+
let boxInitState: AppState | undefined;
|
213
323
|
if (!skipUpdate) {
|
214
324
|
boxInitState = this.getAppInitState(appId);
|
215
325
|
this.boxManager?.updateBoxState(boxInitState);
|
@@ -225,13 +335,14 @@ export class AppProxy implements PageRemoveService {
|
|
225
335
|
this.fixMobileSize();
|
226
336
|
}, SETUP_APP_DELAY);
|
227
337
|
});
|
228
|
-
this.boxManager?.createBox({
|
338
|
+
const box = this.boxManager?.createBox({
|
229
339
|
appId: appId,
|
230
340
|
app,
|
231
341
|
options,
|
232
342
|
canOperate: this.manager.canOperate,
|
233
343
|
smartPosition: this.isAddApp,
|
234
344
|
});
|
345
|
+
this.box$.setValue(box);
|
235
346
|
if (this.isAddApp && this.box) {
|
236
347
|
this.store.updateAppState(appId, AppAttributes.ZIndex, this.box.zIndex);
|
237
348
|
this.boxManager.focusBox({ appId }, false);
|
@@ -246,12 +357,14 @@ export class AppProxy implements PageRemoveService {
|
|
246
357
|
private fixMobileSize() {
|
247
358
|
const box = this.boxManager?.getBox(this.id);
|
248
359
|
if (box) {
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
360
|
+
if (!box.minimized) {
|
361
|
+
this.boxManager?.resizeBox({
|
362
|
+
appId: this.id,
|
363
|
+
width: box.intrinsicWidth + 0.001,
|
364
|
+
height: box.intrinsicHeight + 0.001,
|
365
|
+
skipUpdate: true,
|
366
|
+
});
|
367
|
+
}
|
255
368
|
}
|
256
369
|
}
|
257
370
|
|
@@ -296,30 +409,18 @@ export class AppProxy implements PageRemoveService {
|
|
296
409
|
}
|
297
410
|
}
|
298
411
|
|
299
|
-
public getAppInitState = (id: string) => {
|
412
|
+
public getAppInitState = (id: string): AppState | undefined => {
|
300
413
|
const attrs = this.store.getAppState(id);
|
301
414
|
if (!attrs) return;
|
302
|
-
const position = attrs?.[AppAttributes.Position];
|
303
415
|
const focus = this.store.focus;
|
304
|
-
const size = attrs?.[AppAttributes.Size];
|
305
|
-
const sceneIndex = attrs?.[AppAttributes.SceneIndex];
|
306
416
|
const maximized = this.attributes?.["maximized"];
|
307
417
|
const minimized = this.attributes?.["minimized"];
|
308
|
-
|
309
|
-
|
310
|
-
if (position) {
|
311
|
-
payload = { ...payload, id: id, x: position.x, y: position.y };
|
312
|
-
}
|
418
|
+
let payload = { maximized, minimized, id } as AppState;
|
419
|
+
const state = omitBy(attrs, isUndefined);
|
313
420
|
if (focus === id) {
|
314
421
|
payload = { ...payload, focus: true };
|
315
422
|
}
|
316
|
-
|
317
|
-
payload = { ...payload, width: size.width, height: size.height };
|
318
|
-
}
|
319
|
-
if (sceneIndex) {
|
320
|
-
payload = { ...payload, sceneIndex };
|
321
|
-
}
|
322
|
-
return payload;
|
423
|
+
return Object.assign(payload, state);;
|
323
424
|
};
|
324
425
|
|
325
426
|
public emitAppSceneStateChange(sceneState: SceneState) {
|
@@ -376,32 +477,34 @@ export class AppProxy implements PageRemoveService {
|
|
376
477
|
}
|
377
478
|
|
378
479
|
private appAttributesUpdateListener = (appId: string) => {
|
379
|
-
this.
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
this.
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
480
|
+
this.sideEffectManager.add(() => [
|
481
|
+
this.manager.refresher.add(appId, () => {
|
482
|
+
return autorun(() => {
|
483
|
+
const attrs = this.manager.attributes[appId];
|
484
|
+
if (attrs) {
|
485
|
+
this.appEmitter.emit("attributesUpdate", attrs);
|
486
|
+
}
|
487
|
+
});
|
488
|
+
}),
|
489
|
+
this.manager.refresher.add(this.stateKey, () => {
|
490
|
+
return autorun(() => {
|
491
|
+
const appState = this.appAttributes?.state;
|
492
|
+
if (appState?.zIndex > 0 && appState.zIndex !== this.box?.zIndex) {
|
493
|
+
this.boxManager?.setZIndex(appId, appState.zIndex);
|
494
|
+
}
|
495
|
+
});
|
496
|
+
}),
|
497
|
+
this.manager.refresher.add(`${appId}-fullPath`, () => {
|
498
|
+
return autorun(() => {
|
499
|
+
const fullPath = this.appAttributes?.fullPath;
|
500
|
+
this.setFocusScenePathHandler(fullPath);
|
501
|
+
if (this.fullPath$.value !== fullPath) {
|
502
|
+
this.notifyPageStateChange();
|
503
|
+
this.fullPath$.setValue(fullPath);
|
504
|
+
}
|
505
|
+
});
|
506
|
+
}),
|
507
|
+
]);
|
405
508
|
};
|
406
509
|
|
407
510
|
private setFocusScenePathHandler = debounce((fullPath: string | undefined) => {
|
@@ -428,6 +531,7 @@ export class AppProxy implements PageRemoveService {
|
|
428
531
|
|
429
532
|
private createView(): View {
|
430
533
|
const view = this.viewManager.createView(this.id);
|
534
|
+
this.view$.setValue(view);
|
431
535
|
this.setViewFocusScenePath();
|
432
536
|
return view;
|
433
537
|
}
|
@@ -477,10 +581,37 @@ export class AppProxy implements PageRemoveService {
|
|
477
581
|
const fullPath = this._pageState.getFullPath(index);
|
478
582
|
if (fullPath) {
|
479
583
|
this.setFullPath(fullPath);
|
584
|
+
setScenePath(this.manager.room, fullPath);
|
480
585
|
}
|
481
586
|
}
|
482
587
|
}
|
483
588
|
|
589
|
+
public storeCamera = (camera: ICamera) => {
|
590
|
+
this.store.updateAppAttributes(this.id, Fields.Camera, camera);
|
591
|
+
};
|
592
|
+
|
593
|
+
public storeSize = (size: ISize) => {
|
594
|
+
this.store.updateAppAttributes(this.id, Fields.Size, size);
|
595
|
+
};
|
596
|
+
|
597
|
+
public updateSize = (width: number, height: number) => {
|
598
|
+
const iSize = {
|
599
|
+
id: this.manager.uid,
|
600
|
+
width, height
|
601
|
+
}
|
602
|
+
this.store.updateAppAttributes(this.id, Fields.Size, iSize);
|
603
|
+
this.size$.setValue(iSize);
|
604
|
+
}
|
605
|
+
|
606
|
+
public moveCamera = (camera: Partial<ICamera>) => {
|
607
|
+
if (!this.camera$.value) {
|
608
|
+
return;
|
609
|
+
}
|
610
|
+
const nextCamera = { ...this.camera$.value, ...camera, id: this.uid };
|
611
|
+
this.storeCamera(nextCamera);
|
612
|
+
this.camera$.setValue(nextCamera);
|
613
|
+
};
|
614
|
+
|
484
615
|
public async destroy(
|
485
616
|
needCloseBox: boolean,
|
486
617
|
cleanAttrs: boolean,
|
@@ -496,6 +627,7 @@ export class AppProxy implements PageRemoveService {
|
|
496
627
|
console.error("[WindowManager]: notifyApp error", error.message, error.stack);
|
497
628
|
}
|
498
629
|
this.appEmitter.clearListeners();
|
630
|
+
this.sideEffectManager.flushAll();
|
499
631
|
emitter.emit(`destroy-${this.id}` as any, { error });
|
500
632
|
if (needCloseBox) {
|
501
633
|
this.boxManager?.closeBox(this.id, skipUpdate);
|
@@ -510,11 +642,47 @@ export class AppProxy implements PageRemoveService {
|
|
510
642
|
|
511
643
|
this.viewManager.destroyView(this.id);
|
512
644
|
this.manager.appStatus.delete(this.id);
|
513
|
-
this.
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
this.sideEffectManager.
|
645
|
+
this.valManager.destroy();
|
646
|
+
}
|
647
|
+
|
648
|
+
private addCameraReaction = () => {
|
649
|
+
this.sideEffectManager.add(() =>
|
650
|
+
this.manager.refresher.add(`${this.id}-camera`, () =>
|
651
|
+
reaction(
|
652
|
+
() => this.appAttributes?.camera,
|
653
|
+
camera => {
|
654
|
+
if (camera) {
|
655
|
+
const rawCamera = toJS(camera);
|
656
|
+
if (!isEqual(rawCamera, this.camera$.value)) {
|
657
|
+
this.camera$.setValue(rawCamera);
|
658
|
+
}
|
659
|
+
}
|
660
|
+
}
|
661
|
+
)
|
662
|
+
)
|
663
|
+
, "camera");
|
664
|
+
}
|
665
|
+
|
666
|
+
private addSizeReaction = () => {
|
667
|
+
this.sideEffectManager.add(() =>
|
668
|
+
this.manager.refresher.add(`${this.id}-size`, () =>
|
669
|
+
reaction(
|
670
|
+
() => this.appAttributes?.size,
|
671
|
+
size => {
|
672
|
+
if (size) {
|
673
|
+
const rawSize = toJS(size);
|
674
|
+
if (!isEqual(rawSize, this.size$.value)) {
|
675
|
+
this.size$.setValue(rawSize);
|
676
|
+
}
|
677
|
+
}
|
678
|
+
}
|
679
|
+
)
|
680
|
+
)
|
681
|
+
, "size");
|
682
|
+
}
|
683
|
+
|
684
|
+
public onFocus = () => {
|
685
|
+
this.setScenePath();
|
518
686
|
}
|
519
687
|
|
520
688
|
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