@netless/window-manager 1.0.0-canary.5 → 1.0.0-canary.52

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 (95) hide show
  1. package/README.md +30 -6
  2. package/dist/index.cjs.js +12477 -34
  3. package/dist/index.es.js +6842 -10498
  4. package/dist/index.umd.js +12485 -46
  5. package/dist/{App → src/App}/AppContext.d.ts +12 -7
  6. package/dist/{App → src/App}/AppPageStateImpl.d.ts +0 -0
  7. package/dist/{App → src/App}/AppProxy.d.ts +29 -11
  8. package/dist/{App → src/App}/MagixEvent/index.d.ts +0 -0
  9. package/dist/{App → src/App}/Storage/StorageEvent.d.ts +0 -0
  10. package/dist/{App → src/App}/Storage/index.d.ts +0 -0
  11. package/dist/{App → src/App}/Storage/typings.d.ts +0 -0
  12. package/dist/{App → src/App}/Storage/utils.d.ts +0 -0
  13. package/dist/src/App/WhiteboardView.d.ts +27 -0
  14. package/dist/{App → src/App}/index.d.ts +1 -0
  15. package/dist/src/App/type.d.ts +21 -0
  16. package/dist/{AppListener.d.ts → src/AppListener.d.ts} +2 -2
  17. package/dist/{AppManager.d.ts → src/AppManager.d.ts} +6 -5
  18. package/dist/{AttributesDelegate.d.ts → src/AttributesDelegate.d.ts} +5 -2
  19. package/dist/{BoxEmitter.d.ts → src/BoxEmitter.d.ts} +0 -0
  20. package/dist/{BoxManager.d.ts → src/BoxManager.d.ts} +12 -6
  21. package/dist/{BuiltinApps.d.ts → src/BuiltinApps.d.ts} +3 -0
  22. package/dist/{Cursor → src/Cursor}/Cursor.d.ts +0 -0
  23. package/dist/{Cursor → src/Cursor}/icons.d.ts +0 -0
  24. package/dist/{Cursor → src/Cursor}/index.d.ts +3 -3
  25. package/dist/{Helper.d.ts → src/Helper.d.ts} +4 -8
  26. package/dist/{InternalEmitter.d.ts → src/InternalEmitter.d.ts} +3 -4
  27. package/dist/{Page → src/Page}/PageController.d.ts +2 -1
  28. package/dist/{Page → src/Page}/index.d.ts +0 -0
  29. package/dist/{PageState.d.ts → src/PageState.d.ts} +0 -0
  30. package/dist/{ReconnectRefresher.d.ts → src/ReconnectRefresher.d.ts} +0 -0
  31. package/dist/{RedoUndo.d.ts → src/RedoUndo.d.ts} +0 -0
  32. package/dist/{Register → src/Register}/index.d.ts +4 -2
  33. package/dist/{Register → src/Register}/loader.d.ts +1 -1
  34. package/dist/src/Register/storage.d.ts +11 -0
  35. package/dist/{Utils → src/Utils}/AppCreateQueue.d.ts +0 -0
  36. package/dist/{Utils → src/Utils}/Common.d.ts +0 -0
  37. package/dist/{Utils → src/Utils}/Reactive.d.ts +0 -0
  38. package/dist/{Utils → src/Utils}/RoomHacker.d.ts +0 -0
  39. package/dist/{Utils → src/Utils}/error.d.ts +1 -1
  40. package/dist/{Utils → src/Utils}/log.d.ts +0 -0
  41. package/dist/src/View/CameraSynchronizer.d.ts +19 -0
  42. package/dist/{View → src/View}/MainView.d.ts +18 -7
  43. package/dist/{View → src/View}/ViewManager.d.ts +0 -0
  44. package/dist/src/View/ViewSync.d.ts +29 -0
  45. package/dist/{callback.d.ts → src/callback.d.ts} +10 -1
  46. package/dist/{constants.d.ts → src/constants.d.ts} +10 -5
  47. package/dist/src/image.d.ts +19 -0
  48. package/dist/{index.d.ts → src/index.d.ts} +49 -14
  49. package/dist/src/shim.d.ts +11 -0
  50. package/dist/{typings.d.ts → src/typings.d.ts} +12 -3
  51. package/dist/style.css +795 -1
  52. package/docs/app-context.md +155 -27
  53. package/docs/mirgrate-to-1.0.md +68 -0
  54. package/package.json +23 -19
  55. package/playwright.config.ts +29 -0
  56. package/pnpm-lock.yaml +3078 -4412
  57. package/src/App/AppContext.ts +62 -29
  58. package/src/App/AppProxy.ts +235 -113
  59. package/src/App/WhiteboardView.ts +34 -12
  60. package/src/App/index.ts +1 -0
  61. package/src/App/type.ts +22 -0
  62. package/src/AppListener.ts +30 -21
  63. package/src/AppManager.ts +68 -45
  64. package/src/AttributesDelegate.ts +6 -3
  65. package/src/BoxManager.ts +76 -38
  66. package/src/BuiltinApps.ts +9 -8
  67. package/src/Cursor/Cursor.ts +7 -3
  68. package/src/Cursor/index.ts +7 -8
  69. package/src/Helper.ts +25 -7
  70. package/src/InternalEmitter.ts +3 -4
  71. package/src/Page/PageController.ts +2 -1
  72. package/src/PageState.ts +1 -1
  73. package/src/ReconnectRefresher.ts +6 -2
  74. package/src/Register/index.ts +36 -14
  75. package/src/Register/loader.ts +20 -9
  76. package/src/Register/storage.ts +26 -5
  77. package/src/Utils/Common.ts +3 -0
  78. package/src/Utils/Reactive.ts +27 -26
  79. package/src/Utils/RoomHacker.ts +3 -0
  80. package/src/Utils/error.ts +2 -2
  81. package/src/View/CameraSynchronizer.ts +41 -38
  82. package/src/View/MainView.ts +117 -76
  83. package/src/View/ViewSync.ts +123 -6
  84. package/src/callback.ts +6 -1
  85. package/src/constants.ts +8 -3
  86. package/src/index.ts +201 -63
  87. package/src/style.css +3 -46
  88. package/src/typings.ts +14 -3
  89. package/vite.config.js +12 -7
  90. package/dist/App/AppViewSync.d.ts +0 -11
  91. package/dist/App/WhiteboardView.d.ts +0 -21
  92. package/dist/Register/storage.d.ts +0 -8
  93. package/dist/View/CameraSynchronizer.d.ts +0 -17
  94. package/dist/View/ViewSync.d.ts +0 -7
  95. package/src/App/AppViewSync.ts +0 -69
@@ -1,36 +1,58 @@
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";
8
- import type { Camera } from "white-web-sdk";
9
+ import type { Camera, View } from "white-web-sdk";
10
+ import type { TeleBoxRect } from "@netless/telebox-insider";
11
+ import type { ICamera, ISize } from "../AttributesDelegate";
12
+
13
+ export type WhiteBoardViewCamera = Omit<ICamera, "id">;
14
+ export type WhiteBoardViewRect = Omit<ISize, "id">;
9
15
 
10
16
  export class WhiteBoardView implements PageController {
11
17
  public readonly pageState$: ReadonlyVal<PageState>;
18
+ public readonly baseCamera$: ReadonlyVal<WhiteBoardViewCamera>;
19
+ public readonly baseRect$: ReadonlyVal<WhiteBoardViewRect | undefined>;
12
20
 
13
21
  constructor(
22
+ public view: View,
14
23
  protected appContext: AppContext,
15
24
  protected appProxy: AppProxy,
16
- private removeViewWrapper: () => void
25
+ public ensureSize: (size: number) => void
17
26
  ) {
18
27
  const pageState$ = new Val<PageState>(appProxy.pageState);
28
+ const baseRect$ = new Val<WhiteBoardViewRect | undefined>(appProxy.size$.value);
29
+ const pickCamera = (camera: Camera | ICamera) =>
30
+ pick(camera, ["centerX", "centerY", "scale"]);
31
+ const camera$ = new Val<WhiteBoardViewCamera>(pickCamera(this.view.camera));
32
+ this.baseRect$ = baseRect$;
19
33
  this.pageState$ = pageState$;
20
- appProxy.appEmitter.on("pageStateChange", pageState => {
21
- pageState$.setValue(pageState);
22
- });
23
- }
24
-
25
- public get view() {
26
- return this.appContext.view;
34
+ this.baseCamera$ = camera$;
35
+ this.appProxy.sideEffectManager.add(() => [
36
+ appProxy.appEmitter.on("pageStateChange", pageState => pageState$.setValue(pageState)),
37
+ appProxy.camera$.subscribe(camera => {
38
+ if (camera) {
39
+ camera$.setValue(pickCamera(camera));
40
+ }
41
+ }),
42
+ appProxy.size$.subscribe(size => {
43
+ if (size) {
44
+ baseRect$.setValue(pick(size, ["width", "height"]));
45
+ }
46
+ }),
47
+ ]);
48
+ view.disableCameraTransform = true;
27
49
  }
28
50
 
29
51
  public get pageState() {
30
52
  return this.pageState$.value;
31
53
  }
32
54
 
33
- public moveCamera(camera: Camera) {
55
+ public moveCamera(camera: Partial<WhiteBoardViewCamera>) {
34
56
  this.appProxy.moveCamera(camera);
35
57
  }
36
58
 
@@ -79,7 +101,7 @@ export class WhiteBoardView implements PageController {
79
101
  return this.appProxy.removeSceneByIndex(needRemoveIndex);
80
102
  };
81
103
 
82
- public destroy() {
83
- this.removeViewWrapper();
104
+ public setBaseRect(rect: Omit<TeleBoxRect, "x" | "y">) {
105
+ this.appProxy.updateSize(rect.width, rect.height);
84
106
  }
85
107
  }
package/src/App/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./AppProxy";
2
2
  export * from "./AppContext";
3
3
  export * from "./WhiteboardView";
4
+ export * from "./type";
@@ -0,0 +1,22 @@
1
+
2
+ export type AppState = {
3
+ id: string;
4
+ focus?: boolean;
5
+ SceneIndex?: number;
6
+ draggable?: boolean;
7
+ position?: {
8
+ x: number;
9
+ y: number;
10
+ }
11
+ ratio?: number;
12
+ resizable?: boolean;
13
+ size?: {
14
+ width: number;
15
+ height: number;
16
+ }
17
+ stageRatio?: number;
18
+ visible?: boolean;
19
+ zIndex?: number;
20
+ maximized: boolean | null;
21
+ minimized: boolean | null;
22
+ }
@@ -1,11 +1,11 @@
1
1
  import { callbacks } from "./callback";
2
2
  import { emitter } from "./InternalEmitter";
3
3
  import { Events, MagixEventName } from "./constants";
4
- import { isEqual, omit } from "lodash";
5
4
  import { setViewFocusScenePath } from "./Utils/Common";
6
- import type { AnimationMode, Camera, Event } from "white-web-sdk";
5
+ import type { AnimationMode, Camera, Event, Rectangle } from "white-web-sdk";
7
6
  import type { AppManager } from "./AppManager";
8
7
  import type { TeleBoxState } from "@netless/telebox-insider";
8
+ import { computedMinScale } from "./View/CameraSynchronizer";
9
9
 
10
10
  type SetAppFocusIndex = {
11
11
  type: "main" | "app";
@@ -50,14 +50,6 @@ export class AppListeners {
50
50
  this.setMainViewScenePathHandler(data.payload);
51
51
  break;
52
52
  }
53
- case Events.MoveCamera: {
54
- this.moveCameraHandler(data.payload);
55
- break;
56
- }
57
- case Events.MoveCameraToContain: {
58
- this.moveCameraToContainHandler(data.payload);
59
- break;
60
- }
61
53
  case Events.CursorMove: {
62
54
  this.cursorMoveHandler(data.payload);
63
55
  break;
@@ -78,6 +70,18 @@ export class AppListeners {
78
70
  this.setAppFocusViewIndexHandler(data.payload);
79
71
  break;
80
72
  }
73
+ case Events.InvokeAttributesUpdateCallback: {
74
+ this.manager.attributesUpdateCallback(this.manager.attributes.apps);
75
+ break;
76
+ }
77
+ case Events.MoveCamera: {
78
+ this.moveCameraHandler(data.payload);
79
+ break;
80
+ }
81
+ case Events.MoveCameraToContain: {
82
+ this.moveCameraToContainHandler(data.payload);
83
+ break;
84
+ }
81
85
  default:
82
86
  break;
83
87
  }
@@ -102,17 +106,6 @@ export class AppListeners {
102
106
  callbacks.emit("mainViewScenePathChange", nextScenePath);
103
107
  };
104
108
 
105
- private moveCameraHandler = (
106
- payload: Camera & { animationMode?: AnimationMode | undefined }
107
- ) => {
108
- if (isEqual(omit(payload, ["animationMode"]), { ...this.manager.mainView.camera })) return;
109
- this.manager.mainView.moveCamera(payload);
110
- };
111
-
112
- private moveCameraToContainHandler = (payload: any) => {
113
- this.manager.mainView.moveCameraToContain(payload);
114
- };
115
-
116
109
  private cursorMoveHandler = (payload: any) => {
117
110
  emitter.emit("cursorMove", payload);
118
111
  };
@@ -141,4 +134,20 @@ export class AppListeners {
141
134
  }
142
135
  }
143
136
  }
137
+
138
+ private moveCameraHandler = (payload: Camera) => {
139
+ const cameraPayload = payload;
140
+ if (payload.scale) {
141
+ const remoteSize = this.manager.mainViewProxy.size$.value;
142
+ const currentSize = this.manager.boxManager?.stageRect;
143
+ if (remoteSize && currentSize) {
144
+ cameraPayload.scale = payload.scale * computedMinScale(remoteSize, currentSize);
145
+ }
146
+ }
147
+ this.manager.mainView.moveCamera(cameraPayload);
148
+ }
149
+
150
+ private moveCameraToContainHandler = (payload: Rectangle & { animationMode?: AnimationMode }) => {
151
+ this.manager.mainView.moveCameraToContain(payload);
152
+ }
144
153
  }
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 {
@@ -29,15 +30,16 @@ import {
29
30
  removeScenes,
30
31
  setScenePath,
31
32
  setViewFocusScenePath,
33
+ wait,
32
34
  } from "./Utils/Common";
33
35
  import type { ReconnectRefresher } from "./ReconnectRefresher";
34
36
  import type { BoxManager } from "./BoxManager";
35
37
  import type {
36
38
  Displayer,
37
- DisplayerState,
38
39
  Room,
39
40
  ScenesCallbacksNode,
40
41
  SceneState,
42
+ RoomState,
41
43
  } from "white-web-sdk";
42
44
  import type { AddAppParams, BaseInsertParams, TeleBoxRect } from "./index";
43
45
  import type {
@@ -63,10 +65,11 @@ export class AppManager {
63
65
  private appListeners: AppListeners;
64
66
  public boxManager?: BoxManager;
65
67
 
66
- private _prevSceneIndex: number | undefined;
67
- private _prevFocused: string | undefined;
68
68
  private callbacksNode: ScenesCallbacksNode | null = null;
69
69
  private appCreateQueue = new AppCreateQueue();
70
+ private sceneIndex$ = new Val<number | undefined>(undefined);
71
+ private focused$ = new Val<string | undefined>(undefined);
72
+ public members$ = new Val<Member[]>([]);
70
73
 
71
74
  private sideEffectManager = new SideEffectManager();
72
75
 
@@ -119,6 +122,7 @@ export class AppManager {
119
122
  appRegister.setSyncRegisterApp(payload => {
120
123
  this.safeUpdateAttributes([Fields.Registered, payload.kind], payload);
121
124
  });
125
+ this.members$.setValue(serializeRoomMembers(this.displayer.state.roomMembers));
122
126
  }
123
127
 
124
128
  private onRemoveScenes = async (params: RemoveSceneParams) => {
@@ -137,7 +141,7 @@ export class AppManager {
137
141
  sceneName = this.callbacksNode?.scenes[nextIndex];
138
142
  }
139
143
  if (sceneName) {
140
- this.setMainViewScenePath(`${ROOT_DIR}${sceneName}`);
144
+ await this.setMainViewScenePath(`${ROOT_DIR}${sceneName}`);
141
145
  }
142
146
  await this.setMainViewSceneIndex(nextIndex);
143
147
  } else {
@@ -152,7 +156,7 @@ export class AppManager {
152
156
  * 所以需要关掉所有开启了 view 的 app
153
157
  */
154
158
  public async onRootDirRemoved(needClose = true) {
155
- this.setMainViewScenePath(INIT_DIR);
159
+ await this.setMainViewScenePath(INIT_DIR);
156
160
  this.createRootDirScenesCallback();
157
161
 
158
162
  for (const [id, appProxy] of this.appProxies.entries()) {
@@ -160,9 +164,9 @@ export class AppManager {
160
164
  await this.closeApp(id, needClose);
161
165
  }
162
166
  }
163
- // 删除了根目录的 scenes 之后 mainview 需要重新绑定, 否则主白板会不能渲染
167
+ // 删除了根目录的 scenes 之后 main-view 需要重新绑定, 否则主白板会不能渲染
164
168
  this.mainViewProxy.rebind();
165
- emitter.emit("rootDirRemoved");
169
+ await emitter.emit("rootDirRemoved");
166
170
  this.updateRootDirRemoving(false);
167
171
  }
168
172
 
@@ -300,10 +304,6 @@ export class AppManager {
300
304
  return this.room?.uid || "";
301
305
  }
302
306
 
303
- public get members(): Member[] {
304
- return serializeRoomMembers(this.displayer.state.roomMembers);
305
- }
306
-
307
307
  public getMainViewSceneDir() {
308
308
  const scenePath = this.store.getMainViewScenePath();
309
309
  if (scenePath) {
@@ -324,31 +324,31 @@ export class AppManager {
324
324
 
325
325
  this.addAppsChangeListener();
326
326
  this.addAppCloseListener();
327
- this.refresher?.add("maximized", () => {
327
+ this.refresher.add("maximized", () => {
328
328
  return autorun(() => {
329
329
  const maximized = this.attributes.maximized;
330
330
  this.boxManager?.setMaximized(Boolean(maximized));
331
331
  });
332
332
  });
333
- this.refresher?.add("minimized", () => {
333
+ this.refresher.add("minimized", () => {
334
334
  return autorun(() => {
335
335
  const minimized = this.attributes.minimized;
336
336
  this.onMinimized(minimized);
337
337
  });
338
338
  });
339
- this.refresher?.add("mainViewIndex", () => {
339
+ this.refresher.add("mainViewIndex", () => {
340
340
  return autorun(() => {
341
341
  const mainSceneIndex = get(this.attributes, "_mainSceneIndex");
342
342
  this.onMainViewIndexChange(mainSceneIndex);
343
343
  });
344
344
  });
345
- this.refresher?.add("focusedChange", () => {
345
+ this.refresher.add("focusedChange", () => {
346
346
  return autorun(() => {
347
347
  const focused = get(this.attributes, "focus");
348
348
  this.onFocusChange(focused);
349
349
  });
350
350
  });
351
- this.refresher?.add("registeredChange", () => {
351
+ this.refresher.add("registeredChange", () => {
352
352
  return autorun(() => {
353
353
  const registered = get(this.attributes, Fields.Registered);
354
354
  this.onRegisteredChange(registered);
@@ -361,7 +361,7 @@ export class AppManager {
361
361
  }
362
362
  this.displayerWritableListener(!this.room?.isWritable);
363
363
  this.displayer.callbacks.on("onEnableWriteNowChanged", this.displayerWritableListener);
364
- this._prevFocused = this.attributes.focus;
364
+ this.focused$.setValue(this.attributes.focus);
365
365
 
366
366
  this.sideEffectManager.add(() => {
367
367
  const redoUndo = new RedoUndo({
@@ -376,8 +376,8 @@ export class AppManager {
376
376
  private onBoxMove = (payload: BoxMovePayload) => {
377
377
  this.dispatchInternalEvent(Events.AppMove, payload);
378
378
  this.store.updateAppState(payload.appId, AppAttributes.Position, {
379
- x: payload.x,
380
- y: payload.y,
379
+ x: isNaN(payload.x) ? 0 : payload.x,
380
+ y: isNaN(payload.y) ? 0 : payload.y,
381
381
  });
382
382
  };
383
383
 
@@ -407,7 +407,7 @@ export class AppManager {
407
407
  };
408
408
 
409
409
  public addAppsChangeListener = () => {
410
- this.refresher?.add("apps", () => {
410
+ this.refresher.add("apps", () => {
411
411
  return safeListenPropsUpdated(
412
412
  () => this.attributes.apps,
413
413
  () => {
@@ -426,27 +426,28 @@ export class AppManager {
426
426
  };
427
427
 
428
428
  private onMainViewIndexChange = (index: number) => {
429
- if (index !== undefined && this._prevSceneIndex !== index) {
429
+ if (index !== undefined && this.sceneIndex$.value !== index) {
430
430
  callbacks.emit("mainViewSceneIndexChange", index);
431
431
  emitter.emit("changePageState");
432
432
  if (this.callbacksNode) {
433
433
  this.updateSceneState(this.callbacksNode);
434
434
  }
435
- this._prevSceneIndex = index;
435
+ this.sceneIndex$.setValue(index);
436
436
  }
437
437
  };
438
438
 
439
439
  private onFocusChange = (focused: string | undefined) => {
440
- if (this._prevFocused !== focused) {
440
+ if (this.focused$.value !== focused) {
441
441
  callbacks.emit("focusedChange", focused);
442
- emitter.emit("focusedChange", { focused, prev: this._prevFocused });
443
- this._prevFocused = focused;
442
+ emitter.emit("focusedChange", { focused, prev: this.focused$.value });
443
+ this.focused$.setValue(focused);
444
444
  if (focused !== undefined) {
445
445
  this.boxManager?.focusBox({ appId: focused });
446
446
  // 确保 focus 修改的时候, appProxy 已经创建
447
447
  setTimeout(() => {
448
448
  const appProxy = this.appProxies.get(focused);
449
449
  if (appProxy) {
450
+ appProxy.onFocus();
450
451
  appRegister.notifyApp(appProxy.kind, "focus", { appId: focused });
451
452
  }
452
453
  }, 0);
@@ -460,9 +461,9 @@ export class AppManager {
460
461
  );
461
462
 
462
463
  /**
463
- * 插件更新 attributes 时的回调
464
+ * 插件更新 apps 时的回调
464
465
  *
465
- * @param {*} attributes
466
+ * @param {*} apps
466
467
  * @memberof WindowManager
467
468
  */
468
469
  public async _attributesUpdateCallback(apps: any) {
@@ -471,14 +472,28 @@ export class AppManager {
471
472
  if (appIds.length === 0) {
472
473
  this.appCreateQueue.emitReady();
473
474
  }
474
- const appsWithCreatedAt = appIds.map(appId => {
475
- return {
476
- id: appId,
477
- createdAt: apps[appId].createdAt,
478
- };
475
+ let appsWithCreatedAt = appIds.map(appId => {
476
+ // 兼容 1.0 之前创建的应用
477
+ if (apps[appId].setup === true || apps[appId].setup === undefined) {
478
+ return {
479
+ id: appId,
480
+ createdAt: apps[appId].createdAt,
481
+ };
482
+ } else {
483
+ return {};
484
+ }
479
485
  });
486
+ // 兼容 1.0 之前版本的回放, 回放时直接过判断 setup 直接创建 app
487
+ if (this.isReplay) {
488
+ appsWithCreatedAt = appIds.map(appId => {
489
+ return {
490
+ id: appId,
491
+ createdAt: apps[appId].createdAt,
492
+ };
493
+ });
494
+ }
480
495
  for (const { id } of orderBy(appsWithCreatedAt, "createdAt", "asc")) {
481
- if (!this.appProxies.has(id) && !this.appStatus.has(id)) {
496
+ if (id && !this.appProxies.has(id) && !this.appStatus.has(id)) {
482
497
  const app = apps[id];
483
498
  try {
484
499
  const appAttributes = this.attributes[id];
@@ -536,6 +551,7 @@ export class AppManager {
536
551
 
537
552
  public setBoxManager(boxManager: BoxManager) {
538
553
  this.boxManager = boxManager;
554
+ this.mainViewProxy.createViewSync();
539
555
  }
540
556
 
541
557
  public resetMaximized() {
@@ -565,11 +581,14 @@ export class AppManager {
565
581
  public bindMainView(divElement: HTMLDivElement, disableCameraTransform: boolean) {
566
582
  const mainView = this.mainViewProxy.view;
567
583
  mainView.disableCameraTransform = disableCameraTransform;
568
- mainView.divElement = divElement;
584
+ // 延迟挂载 mainView dom, 避免因为同步 camera 的闪动
585
+ wait(30).then(() => {
586
+ mainView.divElement = divElement;
587
+ emitter.emit("mainViewMounted");
588
+ });
569
589
  if (!mainView.focusScenePath) {
570
590
  this.setMainViewFocusPath();
571
591
  }
572
- emitter.emit("mainViewMounted");
573
592
  }
574
593
 
575
594
  public setMainViewFocusPath(scenePath?: string) {
@@ -589,6 +608,7 @@ export class AppManager {
589
608
 
590
609
  public async addApp(params: AddAppParams, isDynamicPPT: boolean): Promise<string | undefined> {
591
610
  log("addApp", params);
611
+ // 初始化 app 的属性创建
592
612
  const { appId, needFocus } = await this.beforeAddApp(params, isDynamicPPT);
593
613
  const appProxy = await this.baseInsertApp(params, appId, true, needFocus);
594
614
  this.afterAddApp(appProxy);
@@ -600,6 +620,7 @@ export class AppManager {
600
620
  this.appStatus.set(appId, AppStatus.StartCreate);
601
621
  const attrs = params.attributes ?? {};
602
622
  this.safeUpdateAttributes([appId], attrs);
623
+ // 初始化的时候时需要一些异步的工作, 完成后其他端才可以创建
603
624
  this.store.setupAppAttributes(params, appId, isDynamicPPT);
604
625
  const needFocus = !this.boxManager?.minimized;
605
626
  if (needFocus) {
@@ -651,7 +672,7 @@ export class AppManager {
651
672
  }
652
673
  }
653
674
 
654
- private displayerStateListener = (state: Partial<DisplayerState>) => {
675
+ private displayerStateListener = (state: Partial<RoomState>) => {
655
676
  const sceneState = state.sceneState;
656
677
  if (sceneState) {
657
678
  const scenePath = sceneState.scenePath;
@@ -666,15 +687,18 @@ export class AppManager {
666
687
  appProxy.appEmitter.emit("roomStateChange", state);
667
688
  });
668
689
  if (state.roomMembers) {
669
- emitter.emit("roomMembersChange", this.members);
690
+ this.members$.setValue(serializeRoomMembers(state.roomMembers));
670
691
  }
671
692
  emitter.emit("observerIdChange", this.displayer.observerId);
693
+ if (state.memberState) {
694
+ emitter.emit("memberStateChange", toJS(state.memberState));
695
+ }
672
696
  };
673
697
 
674
698
  public displayerWritableListener = (isReadonly: boolean) => {
675
699
  const isWritable = !isReadonly;
676
700
  const isManualWritable =
677
- this.windowManger.readonly === undefined || this.windowManger.readonly === false;
701
+ this.windowManger.readonly === undefined || !this.windowManger.readonly;
678
702
  if (this.windowManger.readonly === undefined) {
679
703
  this.boxManager?.setReadonly(isReadonly);
680
704
  } else {
@@ -683,13 +707,10 @@ export class AppManager {
683
707
  this.appProxies.forEach(appProxy => {
684
708
  appProxy.emitAppIsWritableChange();
685
709
  });
686
- if (isWritable === true) {
687
- this.mainView.disableCameraTransform = false;
710
+ if (isWritable) {
688
711
  if (this.room && this.room.disableSerialization === true) {
689
712
  this.room.disableSerialization = false;
690
713
  }
691
- } else {
692
- this.mainView.disableCameraTransform = true;
693
714
  }
694
715
  emitter.emit("writableChange", isWritable);
695
716
  };
@@ -793,6 +814,7 @@ export class AppManager {
793
814
  }
794
815
 
795
816
  public async onReconnected() {
817
+ this.attributesUpdateCallback(this.attributes.apps);
796
818
  const appProxies = Array.from(this.appProxies.values());
797
819
  const reconnected = appProxies.map(appProxy => {
798
820
  return appProxy.onReconnected();
@@ -831,7 +853,8 @@ export class AppManager {
831
853
  }
832
854
  callbacks.clearListeners();
833
855
  this.sideEffectManager.flushAll();
834
- this._prevFocused = undefined;
835
- this._prevSceneIndex = undefined;
856
+ this.sceneIndex$.destroy();
857
+ this.focused$.destroy();
858
+ this.members$.destroy();
836
859
  }
837
860
  }
@@ -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 {
@@ -41,8 +41,11 @@ export type StoreContext = {
41
41
  safeSetAttributes: (attributes: any) => void;
42
42
  }
43
43
 
44
- export type ICamera = Camera & {
44
+ export type ICamera = & {
45
45
  id: string; // room uid
46
+ centerX: number | null,
47
+ centerY: number | null,
48
+ scale: number
46
49
  };
47
50
 
48
51
  export type ISize = Size & {
@@ -95,7 +98,7 @@ export class AttributesDelegate {
95
98
  attrNames.push("scenes");
96
99
  }
97
100
  const options = pick(params.options, attrNames);
98
- const attrs: AppSyncAttributes = { kind: params.kind, options, isDynamicPPT };
101
+ const attrs: AppSyncAttributes = { kind: params.kind, options, isDynamicPPT, setup: false };
99
102
  if (typeof params.src === "string") {
100
103
  attrs.src = params.src;
101
104
  }