@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.
Files changed (47) hide show
  1. package/__mocks__/white-web-sdk.ts +10 -1
  2. package/dist/App/AppContext.d.ts +6 -6
  3. package/dist/App/AppProxy.d.ts +30 -5
  4. package/dist/App/{WhiteBoardView.d.ts → WhiteboardView.d.ts} +10 -1
  5. package/dist/App/index.d.ts +1 -1
  6. package/dist/AppManager.d.ts +5 -5
  7. package/dist/AttributesDelegate.d.ts +11 -16
  8. package/dist/BoxManager.d.ts +3 -3
  9. package/dist/InternalEmitter.d.ts +2 -0
  10. package/dist/Page/PageController.d.ts +1 -0
  11. package/dist/ReconnectRefresher.d.ts +1 -1
  12. package/dist/Utils/Common.d.ts +1 -0
  13. package/dist/Utils/Reactive.d.ts +2 -0
  14. package/dist/View/CameraSynchronizer.d.ts +9 -9
  15. package/dist/View/MainView.d.ts +18 -7
  16. package/dist/View/ViewSync.d.ts +24 -0
  17. package/dist/constants.d.ts +6 -1
  18. package/dist/index.cjs.js +12 -12
  19. package/dist/index.d.ts +19 -2
  20. package/dist/index.es.js +791 -380
  21. package/dist/index.umd.js +12 -12
  22. package/dist/style.css +1 -1
  23. package/docs/app-context.md +98 -64
  24. package/docs/develop-app.md +2 -5
  25. package/docs/mirgrate-to-1.0.md +28 -0
  26. package/package.json +3 -3
  27. package/pnpm-lock.yaml +9 -9
  28. package/src/App/AppContext.ts +30 -19
  29. package/src/App/AppProxy.ts +251 -39
  30. package/src/App/{WhiteBoardView.ts → WhiteboardView.ts} +38 -4
  31. package/src/App/index.ts +1 -1
  32. package/src/AppManager.ts +33 -30
  33. package/src/AttributesDelegate.ts +18 -18
  34. package/src/BoxManager.ts +20 -15
  35. package/src/InternalEmitter.ts +2 -0
  36. package/src/Page/PageController.ts +1 -0
  37. package/src/PageState.ts +1 -1
  38. package/src/ReconnectRefresher.ts +2 -1
  39. package/src/Utils/Common.ts +6 -0
  40. package/src/Utils/Reactive.ts +43 -26
  41. package/src/Utils/RoomHacker.ts +3 -0
  42. package/src/View/CameraSynchronizer.ts +43 -30
  43. package/src/View/MainView.ts +106 -81
  44. package/src/View/ViewSync.ts +116 -0
  45. package/src/constants.ts +5 -0
  46. package/src/index.ts +59 -15
  47. package/src/style.css +8 -0
package/src/AppManager.ts CHANGED
@@ -3,7 +3,7 @@ import { AppCreateQueue } from "./Utils/AppCreateQueue";
3
3
  import { AppListeners } from "./AppListener";
4
4
  import { AppProxy } from "./App";
5
5
  import { appRegister } from "./Register";
6
- import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
6
+ import { autorun, isPlayer, isRoom, ScenePathType, toJS } from "white-web-sdk";
7
7
  import { boxEmitter } from "./BoxEmitter";
8
8
  import { calculateNextIndex } from "./Page";
9
9
  import { callbacks } from "./callback";
@@ -18,6 +18,7 @@ import { RedoUndo } from "./RedoUndo";
18
18
  import { serializeRoomMembers } from "./Helper";
19
19
  import { SideEffectManager } from "side-effect-manager";
20
20
  import { ViewManager } from "./View/ViewManager";
21
+ import { Val } from "value-enhancer";
21
22
  import type { SyncRegisterAppPayload } from "./Register";
22
23
  import type { RemoveSceneParams } from "./InternalEmitter";
23
24
  import {
@@ -34,10 +35,10 @@ import type { ReconnectRefresher } from "./ReconnectRefresher";
34
35
  import type { BoxManager } from "./BoxManager";
35
36
  import type {
36
37
  Displayer,
37
- DisplayerState,
38
38
  Room,
39
39
  ScenesCallbacksNode,
40
40
  SceneState,
41
+ RoomState,
41
42
  } from "white-web-sdk";
42
43
  import type { AddAppParams, BaseInsertParams, TeleBoxRect } from "./index";
43
44
  import type {
@@ -56,17 +57,17 @@ export class AppManager {
56
57
  public appStatus: Map<string, AppStatus> = new Map();
57
58
  public store = store;
58
59
  public mainViewProxy: MainViewProxy;
59
- public refresher?: ReconnectRefresher;
60
+ public refresher: ReconnectRefresher;
60
61
  public isReplay = this.windowManger.isReplay;
61
62
  public mainViewScenesLength = 0;
62
63
 
63
64
  private appListeners: AppListeners;
64
65
  public boxManager?: BoxManager;
65
66
 
66
- private _prevSceneIndex: number | undefined;
67
- private _prevFocused: string | undefined;
68
67
  private callbacksNode: ScenesCallbacksNode | null = null;
69
68
  private appCreateQueue = new AppCreateQueue();
69
+ private sceneIndex$ = new Val<number | undefined>(undefined);
70
+ private focused$ = new Val<string | undefined>(undefined);
70
71
 
71
72
  private sideEffectManager = new SideEffectManager();
72
73
 
@@ -137,7 +138,7 @@ export class AppManager {
137
138
  sceneName = this.callbacksNode?.scenes[nextIndex];
138
139
  }
139
140
  if (sceneName) {
140
- this.setMainViewScenePath(`${ROOT_DIR}${sceneName}`);
141
+ await this.setMainViewScenePath(`${ROOT_DIR}${sceneName}`);
141
142
  }
142
143
  await this.setMainViewSceneIndex(nextIndex);
143
144
  } else {
@@ -152,7 +153,7 @@ export class AppManager {
152
153
  * 所以需要关掉所有开启了 view 的 app
153
154
  */
154
155
  public async onRootDirRemoved(needClose = true) {
155
- this.setMainViewScenePath(INIT_DIR);
156
+ await this.setMainViewScenePath(INIT_DIR);
156
157
  this.createRootDirScenesCallback();
157
158
 
158
159
  for (const [id, appProxy] of this.appProxies.entries()) {
@@ -160,9 +161,9 @@ export class AppManager {
160
161
  await this.closeApp(id, needClose);
161
162
  }
162
163
  }
163
- // 删除了根目录的 scenes 之后 mainview 需要重新绑定, 否则主白板会不能渲染
164
+ // 删除了根目录的 scenes 之后 main-view 需要重新绑定, 否则主白板会不能渲染
164
165
  this.mainViewProxy.rebind();
165
- emitter.emit("rootDirRemoved");
166
+ await emitter.emit("rootDirRemoved");
166
167
  this.updateRootDirRemoving(false);
167
168
  }
168
169
 
@@ -324,31 +325,31 @@ export class AppManager {
324
325
 
325
326
  this.addAppsChangeListener();
326
327
  this.addAppCloseListener();
327
- this.refresher?.add("maximized", () => {
328
+ this.refresher.add("maximized", () => {
328
329
  return autorun(() => {
329
330
  const maximized = this.attributes.maximized;
330
331
  this.boxManager?.setMaximized(Boolean(maximized));
331
332
  });
332
333
  });
333
- this.refresher?.add("minimized", () => {
334
+ this.refresher.add("minimized", () => {
334
335
  return autorun(() => {
335
336
  const minimized = this.attributes.minimized;
336
337
  this.onMinimized(minimized);
337
338
  });
338
339
  });
339
- this.refresher?.add("mainViewIndex", () => {
340
+ this.refresher.add("mainViewIndex", () => {
340
341
  return autorun(() => {
341
342
  const mainSceneIndex = get(this.attributes, "_mainSceneIndex");
342
343
  this.onMainViewIndexChange(mainSceneIndex);
343
344
  });
344
345
  });
345
- this.refresher?.add("focusedChange", () => {
346
+ this.refresher.add("focusedChange", () => {
346
347
  return autorun(() => {
347
348
  const focused = get(this.attributes, "focus");
348
349
  this.onFocusChange(focused);
349
350
  });
350
351
  });
351
- this.refresher?.add("registeredChange", () => {
352
+ this.refresher.add("registeredChange", () => {
352
353
  return autorun(() => {
353
354
  const registered = get(this.attributes, Fields.Registered);
354
355
  this.onRegisteredChange(registered);
@@ -361,7 +362,7 @@ export class AppManager {
361
362
  }
362
363
  this.displayerWritableListener(!this.room?.isWritable);
363
364
  this.displayer.callbacks.on("onEnableWriteNowChanged", this.displayerWritableListener);
364
- this._prevFocused = this.attributes.focus;
365
+ this.focused$.setValue(this.attributes.focus);
365
366
 
366
367
  this.sideEffectManager.add(() => {
367
368
  const redoUndo = new RedoUndo({
@@ -426,27 +427,28 @@ export class AppManager {
426
427
  };
427
428
 
428
429
  private onMainViewIndexChange = (index: number) => {
429
- if (index !== undefined && this._prevSceneIndex !== index) {
430
+ if (index !== undefined && this.sceneIndex$.value !== index) {
430
431
  callbacks.emit("mainViewSceneIndexChange", index);
431
432
  emitter.emit("changePageState");
432
433
  if (this.callbacksNode) {
433
434
  this.updateSceneState(this.callbacksNode);
434
435
  }
435
- this._prevSceneIndex = index;
436
+ this.sceneIndex$.setValue(index);
436
437
  }
437
438
  };
438
439
 
439
440
  private onFocusChange = (focused: string | undefined) => {
440
- if (this._prevFocused !== focused) {
441
+ if (this.focused$.value !== focused) {
441
442
  callbacks.emit("focusedChange", focused);
442
- emitter.emit("focusedChange", { focused, prev: this._prevFocused });
443
- this._prevFocused = focused;
443
+ emitter.emit("focusedChange", { focused, prev: this.focused$.value });
444
+ this.focused$.setValue(focused);
444
445
  if (focused !== undefined) {
445
446
  this.boxManager?.focusBox({ appId: focused });
446
447
  // 确保 focus 修改的时候, appProxy 已经创建
447
448
  setTimeout(() => {
448
449
  const appProxy = this.appProxies.get(focused);
449
450
  if (appProxy) {
451
+ appProxy.onFocus();
450
452
  appRegister.notifyApp(appProxy.kind, "focus", { appId: focused });
451
453
  }
452
454
  }, 0);
@@ -460,9 +462,9 @@ export class AppManager {
460
462
  );
461
463
 
462
464
  /**
463
- * 插件更新 attributes 时的回调
465
+ * 插件更新 apps 时的回调
464
466
  *
465
- * @param {*} attributes
467
+ * @param {*} apps
466
468
  * @memberof WindowManager
467
469
  */
468
470
  public async _attributesUpdateCallback(apps: any) {
@@ -536,6 +538,7 @@ export class AppManager {
536
538
 
537
539
  public setBoxManager(boxManager: BoxManager) {
538
540
  this.boxManager = boxManager;
541
+ this.mainViewProxy.createViewSync();
539
542
  }
540
543
 
541
544
  public resetMaximized() {
@@ -651,7 +654,7 @@ export class AppManager {
651
654
  }
652
655
  }
653
656
 
654
- private displayerStateListener = (state: Partial<DisplayerState>) => {
657
+ private displayerStateListener = (state: Partial<RoomState>) => {
655
658
  const sceneState = state.sceneState;
656
659
  if (sceneState) {
657
660
  const scenePath = sceneState.scenePath;
@@ -669,12 +672,15 @@ export class AppManager {
669
672
  emitter.emit("roomMembersChange", this.members);
670
673
  }
671
674
  emitter.emit("observerIdChange", this.displayer.observerId);
675
+ if (state.memberState) {
676
+ emitter.emit("memberStateChange", toJS(state.memberState));
677
+ }
672
678
  };
673
679
 
674
680
  public displayerWritableListener = (isReadonly: boolean) => {
675
681
  const isWritable = !isReadonly;
676
682
  const isManualWritable =
677
- this.windowManger.readonly === undefined || this.windowManger.readonly === false;
683
+ this.windowManger.readonly === undefined || !this.windowManger.readonly;
678
684
  if (this.windowManger.readonly === undefined) {
679
685
  this.boxManager?.setReadonly(isReadonly);
680
686
  } else {
@@ -683,13 +689,10 @@ export class AppManager {
683
689
  this.appProxies.forEach(appProxy => {
684
690
  appProxy.emitAppIsWritableChange();
685
691
  });
686
- if (isWritable === true) {
687
- this.mainView.disableCameraTransform = false;
692
+ if (isWritable) {
688
693
  if (this.room && this.room.disableSerialization === true) {
689
694
  this.room.disableSerialization = false;
690
695
  }
691
- } else {
692
- this.mainView.disableCameraTransform = true;
693
696
  }
694
697
  emitter.emit("writableChange", isWritable);
695
698
  };
@@ -831,7 +834,7 @@ export class AppManager {
831
834
  }
832
835
  callbacks.clearListeners();
833
836
  this.sideEffectManager.flushAll();
834
- this._prevFocused = undefined;
835
- this._prevSceneIndex = undefined;
837
+ this.sceneIndex$.destroy();
838
+ this.focused$.destroy();
836
839
  }
837
840
  }
@@ -2,7 +2,7 @@ import { AppAttributes } from "./constants";
2
2
  import { get, pick } from "lodash";
3
3
  import { setViewFocusScenePath } from "./Utils/Common";
4
4
  import type { AddAppParams, AppSyncAttributes } from "./index";
5
- import type { Camera, Size, View } from "white-web-sdk";
5
+ import type { Size, View } from "white-web-sdk";
6
6
  import type { Cursor } from "./Cursor/Cursor";
7
7
 
8
8
  export enum Fields {
@@ -18,6 +18,8 @@ export enum Fields {
18
18
  CursorState = "cursorState",
19
19
  FullPath = "fullPath",
20
20
  Registered = "registered",
21
+ Camera = "camera",
22
+ Size = "size",
21
23
  }
22
24
 
23
25
  export type Apps = {
@@ -39,9 +41,16 @@ export type StoreContext = {
39
41
  safeSetAttributes: (attributes: any) => void;
40
42
  }
41
43
 
42
- export type ICamera = Camera & { id: string };
44
+ export type ICamera = & {
45
+ id: string; // room uid
46
+ centerX: number | null,
47
+ centerY: number | null,
48
+ scale: number
49
+ };
43
50
 
44
- export type ISize = Size & { id: string };
51
+ export type ISize = Size & {
52
+ id: string; // room uid
53
+ };
45
54
 
46
55
  export class AttributesDelegate {
47
56
 
@@ -108,6 +117,10 @@ export class AttributesDelegate {
108
117
  }
109
118
  }
110
119
 
120
+ public updateAppAttributes(appId: string, key: string, value: any) {
121
+ this.context.safeUpdateAttributes([Fields.Apps, appId, key], value);
122
+ }
123
+
111
124
  public cleanAppAttributes(id: string) {
112
125
  this.context.safeUpdateAttributes([Fields.Apps, id], undefined);
113
126
  this.context.safeSetAttributes({ [id]: undefined });
@@ -149,11 +162,11 @@ export class AttributesDelegate {
149
162
  this.context.safeSetAttributes({ _mainSceneIndex: index });
150
163
  }
151
164
 
152
- public getMainViewCamera(): MainViewCamera {
165
+ public getMainViewCamera(): ICamera {
153
166
  return get(this.attributes, [Fields.MainViewCamera]);
154
167
  }
155
168
 
156
- public getMainViewSize(): MainViewSize {
169
+ public getMainViewSize(): ISize {
157
170
  return get(this.attributes, [Fields.MainViewSize]);
158
171
  }
159
172
 
@@ -214,19 +227,6 @@ export class AttributesDelegate {
214
227
  }
215
228
  }
216
229
 
217
- export type MainViewSize = {
218
- id: string;
219
- width: number;
220
- height: number;
221
- };
222
-
223
- export type MainViewCamera = {
224
- id: string;
225
- centerX: number;
226
- centerY: number;
227
- scale: number;
228
- };
229
-
230
230
  export type Cursors = {
231
231
  [key: string]: Cursor;
232
232
  };
package/src/BoxManager.ts CHANGED
@@ -47,11 +47,11 @@ export type CreateTeleBoxManagerConfig = {
47
47
  collectorStyles?: Partial<CSSStyleDeclaration>;
48
48
  prefersColorScheme?: TeleBoxColorScheme;
49
49
  stageRatio?: number;
50
+ highlightStage?: boolean;
50
51
  };
51
52
 
52
53
  export type BoxManagerContext = {
53
54
  safeSetAttributes: (attributes: any) => void;
54
- getMainView: () => View;
55
55
  updateAppState: (appId: string, field: AppAttributes, value: any) => void;
56
56
  emitter: EmitterType;
57
57
  boxEmitter: BoxEmitterType;
@@ -72,7 +72,6 @@ export const createBoxManager = (
72
72
  return new BoxManager(
73
73
  {
74
74
  safeSetAttributes: (attributes: any) => manager.safeSetAttributes(attributes),
75
- getMainView: () => manager.mainView,
76
75
  updateAppState: (...args) => manager.appManager?.store.updateAppState(...args),
77
76
  canOperate: () => manager.canOperate,
78
77
  notifyContainerRectUpdate: (rect: TeleBoxRect) =>
@@ -81,7 +80,7 @@ export const createBoxManager = (
81
80
  setAppFocus: (appId: string) => manager.appManager?.store.setAppFocus(appId, true),
82
81
  callbacks,
83
82
  emitter,
84
- boxEmitter
83
+ boxEmitter,
85
84
  },
86
85
  options
87
86
  );
@@ -100,17 +99,17 @@ export class BoxManager {
100
99
  this.teleBoxManager = this.setupBoxManager(createTeleBoxManagerConfig);
101
100
  this.sideEffectManager.add(() => [
102
101
  // 使用 _xxx$.reaction 订阅修改的值, 不管有没有 skipUpdate, 修改值都会触发回调
103
- this.teleBoxManager._state$.reaction(state => {
102
+ this.teleBoxManager.onValChanged("state", state => {
104
103
  callbacks.emit("boxStateChange", state);
105
104
  emitter.emit("boxStateChange", state);
106
105
  }),
107
- this.teleBoxManager._darkMode$.reaction(darkMode => {
106
+ this.teleBoxManager.onValChanged("darkMode", darkMode => {
108
107
  callbacks.emit("darkModeChange", darkMode);
109
108
  }),
110
- this.teleBoxManager._prefersColorScheme$.reaction(colorScheme => {
109
+ this.teleBoxManager.onValChanged("prefersColorScheme", colorScheme => {
111
110
  callbacks.emit("prefersColorSchemeChange", colorScheme);
112
111
  }),
113
- this.teleBoxManager._minimized$.reaction((minimized, skipUpdate) => {
112
+ this.teleBoxManager.onValChanged("minimized", (minimized, skipUpdate) => {
114
113
  if (skipUpdate) {
115
114
  return;
116
115
  }
@@ -126,7 +125,7 @@ export class BoxManager {
126
125
  }
127
126
  }
128
127
  }),
129
- this.teleBoxManager._maximized$.reaction((maximized, skipUpdate) => {
128
+ this.teleBoxManager.onValChanged("maximized", (maximized, skipUpdate) => {
130
129
  if (skipUpdate) {
131
130
  return;
132
131
  }
@@ -140,7 +139,11 @@ export class BoxManager {
140
139
  this.teleBoxManager.events.on(
141
140
  "intrinsic_move",
142
141
  debounce((box: ReadonlyTeleBox): void => {
143
- boxEmitter.emit("move", { appId: box.id, x: box.intrinsicX, y: box.intrinsicY });
142
+ boxEmitter.emit("move", {
143
+ appId: box.id,
144
+ x: box.intrinsicX,
145
+ y: box.intrinsicY,
146
+ });
144
147
  }, 50)
145
148
  ),
146
149
  this.teleBoxManager.events.on(
@@ -178,10 +181,6 @@ export class BoxManager {
178
181
  ]);
179
182
  }
180
183
 
181
- private get mainView() {
182
- return this.context.getMainView();
183
- }
184
-
185
184
  private get canOperate() {
186
185
  return this.context.canOperate();
187
186
  }
@@ -214,7 +213,11 @@ export class BoxManager {
214
213
  return this.teleBoxManager.stageRect;
215
214
  }
216
215
 
217
- public createBox(params: CreateBoxParams): void {
216
+ public get stageRect$() {
217
+ return this.teleBoxManager._stageRect$;
218
+ }
219
+
220
+ public createBox(params: CreateBoxParams): ReadonlyTeleBox | undefined {
218
221
  if (!this.teleBoxManager) return;
219
222
  let { minwidth = MIN_WIDTH, minheight = MIN_HEIGHT } = params.app.config ?? {};
220
223
  const { width, height } = params.app.config ?? {};
@@ -237,8 +240,9 @@ export class BoxManager {
237
240
  height,
238
241
  id: params.appId,
239
242
  };
240
- this.teleBoxManager.create(createBoxConfig, params.smartPosition);
243
+ const box = this.teleBoxManager.create(createBoxConfig, params.smartPosition);
241
244
  this.context.emitter.emit(`${params.appId}${Events.WindowCreated}` as any);
245
+ return box;
242
246
  }
243
247
 
244
248
  public setupBoxManager(
@@ -250,6 +254,7 @@ export class BoxManager {
250
254
  root: root,
251
255
  fence: false,
252
256
  prefersColorScheme: createTeleBoxManagerConfig?.prefersColorScheme,
257
+ highlightStage: createTeleBoxManagerConfig?.highlightStage,
253
258
  };
254
259
 
255
260
  const manager = new TeleBoxManager(initManagerState);
@@ -2,6 +2,7 @@ import Emittery from "emittery";
2
2
  import type { TeleBoxRect } from "@netless/telebox-insider";
3
3
  import type { AppInitState, CursorMovePayload } from "./index";
4
4
  import type { Member } from "./Helper";
5
+ import type { MemberState } from "white-web-sdk";
5
6
 
6
7
  export type RemoveSceneParams = {
7
8
  scenePath: string;
@@ -31,6 +32,7 @@ export type EmitterEvent = {
31
32
  writableChange: boolean;
32
33
  containerSizeRatioUpdate: number;
33
34
  roomMembersChange: Member[];
35
+ memberStateChange: MemberState;
34
36
  };
35
37
 
36
38
  export type EmitterType = Emittery<EmitterEvent>;
@@ -13,6 +13,7 @@ export type PageState = {
13
13
  export interface PageController {
14
14
  nextPage: () => Promise<boolean>;
15
15
  prevPage: () => Promise<boolean>;
16
+ jumpPage: (index: number) => Promise<boolean>;
16
17
  addPage: (params?: AddPageParams) => Promise<void>;
17
18
  removePage: (index: number) => Promise<boolean>;
18
19
  pageState: PageState;
package/src/PageState.ts CHANGED
@@ -6,7 +6,7 @@ import type { PageState } from "./Page";
6
6
  export class PageStateImpl {
7
7
  constructor(private manager: AppManager) {
8
8
  emitter.on("changePageState", () => {
9
- callbacks.emit("pageStateChange", this.toObject());
9
+ callbacks.emit("pageStateChange", this.toObject());
10
10
  });
11
11
  }
12
12
 
@@ -53,7 +53,7 @@ export class ReconnectRefresher {
53
53
 
54
54
  private onReconnected = debounce(() => {
55
55
  this._onReconnected();
56
- }, 3000);
56
+ }, 1000);
57
57
 
58
58
  private _onReconnected = () => {
59
59
  log("onReconnected refresh reactors");
@@ -88,6 +88,7 @@ export class ReconnectRefresher {
88
88
  this.reactors.set(id, func);
89
89
  this.disposers.set(id, func());
90
90
  }
91
+ return () => this.remove(id);
91
92
  }
92
93
 
93
94
  public remove(id: string) {
@@ -30,6 +30,12 @@ export const setViewSceneIndex = (view: View, index: number) => {
30
30
  }
31
31
  };
32
32
 
33
+ export const releaseView = (view: View) => {
34
+ if (!(view as any).didRelease) {
35
+ view.release();
36
+ }
37
+ }
38
+
33
39
  export const setScenePath = (room: Room | undefined, scenePath: string) => {
34
40
  if (room && room.isWritable) {
35
41
  if (room.state.sceneState.scenePath !== scenePath) {
@@ -1,6 +1,7 @@
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
+ import type { Val } from "value-enhancer";
4
5
 
5
6
  // 兼容 13 和 14 版本 SDK
6
7
  export const onObjectByEvent = (event: UpdateEventKind) => {
@@ -12,7 +13,7 @@ export const onObjectByEvent = (event: UpdateEventKind) => {
12
13
  if (kinds.includes(event)) {
13
14
  func();
14
15
  }
15
- }
16
+ };
16
17
  listenUpdated(object, listener);
17
18
  func();
18
19
  return () => unlistenUpdated(object, listener);
@@ -21,43 +22,59 @@ export const onObjectByEvent = (event: UpdateEventKind) => {
21
22
  () => object,
22
23
  () => {
23
24
  func();
24
- }, {
25
+ },
26
+ {
25
27
  fireImmediately: true,
26
28
  }
27
- )
29
+ );
28
30
  }
29
- }
30
- }
31
+ };
32
+ };
31
33
 
32
34
  export const safeListenPropsUpdated = <T>(
33
35
  getProps: () => T,
34
36
  callback: AkkoObjectUpdatedListener<T>,
35
37
  onDestroyed?: (props: unknown) => void
36
- ) => {
38
+ ) => {
37
39
  let disposeListenUpdated: (() => void) | null = null;
38
40
  const disposeReaction = reaction(
39
- getProps,
40
- () => {
41
- if (disposeListenUpdated) {
42
- disposeListenUpdated();
43
- disposeListenUpdated = null;
44
- }
45
- const props = getProps();
46
- if (isObject(props)) {
47
- disposeListenUpdated = () => unlistenUpdated(props, callback);
48
- listenUpdated(props, callback);
49
- } else {
50
- onDestroyed?.(props);
51
- }
52
- },
53
- { fireImmediately: true }
41
+ getProps,
42
+ () => {
43
+ if (disposeListenUpdated) {
44
+ disposeListenUpdated();
45
+ disposeListenUpdated = null;
46
+ }
47
+ const props = getProps();
48
+ if (isObject(props)) {
49
+ disposeListenUpdated = () => unlistenUpdated(props, callback);
50
+ listenUpdated(props, callback);
51
+ } else {
52
+ onDestroyed?.(props);
53
+ }
54
+ },
55
+ { fireImmediately: true }
54
56
  );
55
57
 
56
58
  return () => {
57
- disposeListenUpdated?.();
58
- disposeReaction();
59
+ disposeListenUpdated?.();
60
+ disposeReaction();
59
61
  };
60
- }
62
+ };
61
63
 
62
64
  export const onObjectRemoved = onObjectByEvent(UpdateEventKind.Removed);
63
65
  export const onObjectInserted = onObjectByEvent(UpdateEventKind.Inserted);
66
+
67
+ export const createValSync = <T>(expr: any, Val: Val<T, boolean>, isAddApp: boolean): (() => void) => {
68
+ let skipUpdate = false;
69
+ return reaction(
70
+ expr,
71
+ val => {
72
+ if (isAddApp && !skipUpdate) {
73
+ skipUpdate = true;
74
+ } else {
75
+ Val.setValue(val as T);
76
+ }
77
+ },
78
+ { fireImmediately: true }
79
+ );
80
+ };
@@ -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