@netless/window-manager 0.4.0-canary.3 → 0.4.0-canary.30

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 (88) hide show
  1. package/.idea/inspectionProfiles/Project_Default.xml +7 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/.idea/window-manager.iml +12 -0
  5. package/.vscode/settings.json +1 -0
  6. package/CHANGELOG.md +32 -1
  7. package/README.md +2 -0
  8. package/dist/App/MagixEvent/index.d.ts +29 -0
  9. package/dist/App/Storage/StorageEvent.d.ts +8 -0
  10. package/dist/App/Storage/index.d.ts +39 -0
  11. package/dist/App/Storage/typings.d.ts +22 -0
  12. package/dist/App/Storage/utils.d.ts +5 -0
  13. package/dist/AppContext.d.ts +40 -16
  14. package/dist/AppListener.d.ts +1 -1
  15. package/dist/AppManager.d.ts +26 -12
  16. package/dist/AppProxy.d.ts +7 -8
  17. package/dist/AttributesDelegate.d.ts +2 -2
  18. package/dist/BoxManager.d.ts +6 -3
  19. package/dist/BuiltinApps.d.ts +5 -0
  20. package/dist/ContainerResizeObserver.d.ts +10 -0
  21. package/dist/Cursor/Cursor.d.ts +10 -12
  22. package/dist/Cursor/index.d.ts +6 -16
  23. package/dist/Helper.d.ts +7 -0
  24. package/dist/ReconnectRefresher.d.ts +0 -1
  25. package/dist/Register/storage.d.ts +5 -1
  26. package/dist/Utils/AppCreateQueue.d.ts +11 -0
  27. package/dist/Utils/Common.d.ts +7 -2
  28. package/dist/Utils/Reactive.d.ts +1 -1
  29. package/dist/Utils/RoomHacker.d.ts +3 -3
  30. package/dist/{MainView.d.ts → View/MainView.d.ts} +5 -6
  31. package/dist/View/ViewManager.d.ts +13 -0
  32. package/dist/constants.d.ts +4 -7
  33. package/dist/index.d.ts +36 -14
  34. package/dist/index.es.js +41 -1
  35. package/dist/index.es.js.map +1 -1
  36. package/dist/index.umd.js +41 -1
  37. package/dist/index.umd.js.map +1 -1
  38. package/dist/style.css +1 -1
  39. package/dist/typings.d.ts +3 -2
  40. package/docs/api.md +69 -6
  41. package/docs/concept.md +9 -0
  42. package/docs/replay.md +40 -0
  43. package/package.json +7 -6
  44. package/src/App/MagixEvent/index.ts +68 -0
  45. package/src/App/Storage/StorageEvent.ts +21 -0
  46. package/src/App/Storage/index.ts +289 -0
  47. package/src/App/Storage/typings.ts +23 -0
  48. package/src/App/Storage/utils.ts +17 -0
  49. package/src/AppContext.ts +69 -24
  50. package/src/AppListener.ts +15 -14
  51. package/src/AppManager.ts +261 -83
  52. package/src/AppProxy.ts +53 -64
  53. package/src/AttributesDelegate.ts +2 -2
  54. package/src/BoxManager.ts +40 -24
  55. package/src/BuiltinApps.ts +23 -0
  56. package/src/ContainerResizeObserver.ts +62 -0
  57. package/src/Cursor/Cursor.svelte +25 -21
  58. package/src/Cursor/Cursor.ts +25 -38
  59. package/src/Cursor/icons.ts +2 -0
  60. package/src/Cursor/index.ts +45 -139
  61. package/src/Helper.ts +41 -0
  62. package/src/ReconnectRefresher.ts +0 -5
  63. package/src/Register/index.ts +25 -16
  64. package/src/Register/loader.ts +2 -2
  65. package/src/Register/storage.ts +6 -1
  66. package/src/Utils/AppCreateQueue.ts +54 -0
  67. package/src/Utils/Common.ts +69 -14
  68. package/src/Utils/Reactive.ts +9 -3
  69. package/src/Utils/RoomHacker.ts +44 -14
  70. package/src/{MainView.ts → View/MainView.ts} +25 -36
  71. package/src/View/ViewManager.ts +52 -0
  72. package/src/constants.ts +5 -4
  73. package/src/image/laser-pointer-cursor.svg +17 -0
  74. package/src/index.ts +158 -99
  75. package/src/shim.d.ts +5 -0
  76. package/src/style.css +7 -1
  77. package/src/typings.ts +3 -2
  78. package/vite.config.js +8 -2
  79. package/dist/Base/Context.d.ts +0 -13
  80. package/dist/Base/index.d.ts +0 -7
  81. package/dist/Utils/CameraStore.d.ts +0 -15
  82. package/dist/ViewManager.d.ts +0 -29
  83. package/dist/sdk.d.ts +0 -14
  84. package/src/Base/Context.ts +0 -49
  85. package/src/Base/index.ts +0 -10
  86. package/src/Utils/CameraStore.ts +0 -72
  87. package/src/sdk.ts +0 -39
  88. package/src/viewManager.ts +0 -177
package/src/AppManager.ts CHANGED
@@ -1,26 +1,31 @@
1
- import pRetry from "p-retry";
2
- import { AppAttributes, AppStatus, Events, MagixEventName } from "./constants";
1
+ import { AppAttributes, AppStatus, Events, MagixEventName, ROOT_DIR } from "./constants";
2
+ import { AppCreateQueue } from "./Utils/AppCreateQueue";
3
3
  import { AppListeners } from "./AppListener";
4
4
  import { AppProxy } from "./AppProxy";
5
- import { autorun, isPlayer, isRoom, ScenePathType, ViewVisionMode } from "white-web-sdk";
6
- import { callbacks, emitter, WindowManager } from "./index";
7
- import { CameraStore } from "./Utils/CameraStore";
8
- import { genAppId, makeValidScenePath, setScenePath } from "./Utils/Common";
5
+ import { appRegister } from "./Register";
6
+ import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
7
+ import { callbacks, emitter, reconnectRefresher, WindowManager } from "./index";
8
+ import { get, isInteger, orderBy } from "lodash";
9
9
  import { log } from "./Utils/log";
10
- import { MainViewProxy } from "./MainView";
10
+ import { MainViewProxy } from "./View/MainView";
11
11
  import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
12
- import { reconnectRefresher } from "./ReconnectRefresher";
13
- import { sortBy } from "lodash";
14
12
  import { store } from "./AttributesDelegate";
15
- import { ViewManager } from "./ViewManager";
13
+ import { ViewManager } from "./View/ViewManager";
14
+ import {
15
+ entireScenes,
16
+ genAppId,
17
+ makeValidScenePath,
18
+ parseSceneDir,
19
+ setScenePath,
20
+ setViewFocusScenePath,
21
+ } from "./Utils/Common";
16
22
  import type { ReconnectRefresher } from "./ReconnectRefresher";
17
23
  import type { BoxManager } from "./BoxManager";
18
- import type { Displayer, DisplayerState, Room } from "white-web-sdk";
24
+ import type { Displayer, DisplayerState, Room, ScenesCallbacksNode, View } from "white-web-sdk";
19
25
  import type { AddAppParams, BaseInsertParams, TeleBoxRect, EmitterEvent } from "./index";
20
26
 
21
27
  export class AppManager {
22
28
  public displayer: Displayer;
23
- public cameraStore: CameraStore;
24
29
  public viewManager: ViewManager;
25
30
  public appProxies: Map<string, AppProxy> = new Map();
26
31
  public appStatus: Map<string, AppStatus> = new Map();
@@ -28,10 +33,16 @@ export class AppManager {
28
33
  public mainViewProxy: MainViewProxy;
29
34
  public refresher?: ReconnectRefresher;
30
35
  public isReplay = this.windowManger.isReplay;
36
+ public mainViewScenesLength = 0;
31
37
 
32
38
  private appListeners: AppListeners;
33
39
  public boxManager?: BoxManager;
34
40
 
41
+ private _prevSceneIndex: number | undefined;
42
+ private _prevFocused: string | undefined;
43
+ private callbacksNode: ScenesCallbacksNode | null;
44
+ private appCreateQueue = new AppCreateQueue();
45
+
35
46
  constructor(public windowManger: WindowManager) {
36
47
  this.displayer = windowManger.displayer;
37
48
  this.store.setContext({
@@ -39,9 +50,8 @@ export class AppManager {
39
50
  safeSetAttributes: attributes => this.safeSetAttributes(attributes),
40
51
  safeUpdateAttributes: (keys, val) => this.safeUpdateAttributes(keys, val),
41
52
  });
42
- this.cameraStore = new CameraStore();
43
53
  this.mainViewProxy = new MainViewProxy(this);
44
- this.viewManager = new ViewManager(this);
54
+ this.viewManager = new ViewManager(this.displayer);
45
55
  this.appListeners = new AppListeners(this);
46
56
  this.displayer.callbacks.on(this.eventName, this.displayerStateListener);
47
57
  this.appListeners.addListeners();
@@ -61,6 +71,70 @@ export class AppManager {
61
71
  this.onAppDelete(this.attributes.apps);
62
72
  });
63
73
  }
74
+ emitter.on("removeScenes", scenePath => {
75
+ if (scenePath === ROOT_DIR) {
76
+ this.setMainViewScenePath(ROOT_DIR);
77
+ return;
78
+ }
79
+ const mainViewScenePath = this.store.getMainViewScenePath();
80
+ if (this.room && mainViewScenePath) {
81
+ if (mainViewScenePath === scenePath) {
82
+ this.setMainViewScenePath(ROOT_DIR);
83
+ }
84
+ }
85
+ });
86
+ this.callbacksNode = this.displayer.createScenesCallback(ROOT_DIR, {
87
+ onAddScene: scenesCallback => {
88
+ this.mainViewScenesLength = scenesCallback.scenes.length;
89
+ callbacks.emit("mainViewScenesLengthChange", this.mainViewScenesLength);
90
+ },
91
+ onRemoveScene: scenesCallback => {
92
+ this.mainViewScenesLength = scenesCallback.scenes.length;
93
+ callbacks.emit("mainViewScenesLengthChange", this.mainViewScenesLength);
94
+ },
95
+ });
96
+ if (this.callbacksNode) {
97
+ this.mainViewScenesLength = this.callbacksNode.scenes.length;
98
+ }
99
+ }
100
+
101
+ private get eventName() {
102
+ return isRoom(this.displayer) ? "onRoomStateChanged" : "onPlayerStateChanged";
103
+ }
104
+
105
+ public get attributes() {
106
+ return this.windowManger.attributes;
107
+ }
108
+
109
+ public get canOperate() {
110
+ return this.windowManger.canOperate;
111
+ }
112
+
113
+ public get room() {
114
+ return isRoom(this.displayer) ? (this.displayer as Room) : undefined;
115
+ }
116
+
117
+ public get mainView() {
118
+ return this.mainViewProxy.view;
119
+ }
120
+
121
+ public get focusApp() {
122
+ if (this.store.focus) {
123
+ return this.appProxies.get(this.store.focus);
124
+ }
125
+ }
126
+
127
+ public get uid() {
128
+ return this.room?.uid || "";
129
+ }
130
+
131
+ public getMainViewSceneDir() {
132
+ const scenePath = this.store.getMainViewScenePath();
133
+ if (scenePath) {
134
+ return parseSceneDir(scenePath);
135
+ } else {
136
+ throw new Error("[WindowManager]: mainViewSceneDir not found");
137
+ }
64
138
  }
65
139
 
66
140
  private async onCreated() {
@@ -99,6 +173,38 @@ export class AppManager {
99
173
  }
100
174
  });
101
175
  });
176
+ this.refresher?.add("mainViewIndex", () => {
177
+ return autorun(() => {
178
+ const mainSceneIndex = get(this.attributes, "_mainSceneIndex");
179
+ if (mainSceneIndex !== undefined && this._prevSceneIndex !== mainSceneIndex) {
180
+ callbacks.emit("mainViewSceneIndexChange", mainSceneIndex);
181
+ this._prevSceneIndex = mainSceneIndex;
182
+ }
183
+ });
184
+ });
185
+ this.refresher?.add("focusedChange", () => {
186
+ return autorun(() => {
187
+ const focused = get(this.attributes, "focus");
188
+ if (this._prevFocused !== focused) {
189
+ callbacks.emit("focusedChange", focused);
190
+ this.disposePrevFocusViewRedoUndoListeners(this._prevFocused);
191
+ setTimeout(() => {
192
+ this.addRedoUndoListeners(focused);
193
+ }, 0);
194
+ this._prevFocused = focused;
195
+ if (focused !== undefined) {
196
+ this.boxManager?.focusBox({ appId: focused });
197
+ // 确保 focus 修改的时候, appProxy 已经创建
198
+ setTimeout(() => {
199
+ const appProxy = this.appProxies.get(focused);
200
+ if (appProxy) {
201
+ appRegister.notifyApp(appProxy.kind, "focus", { appId: focused });
202
+ }
203
+ }, 0);
204
+ }
205
+ }
206
+ });
207
+ });
102
208
  if (!this.attributes.apps || Object.keys(this.attributes.apps).length === 0) {
103
209
  const mainScenePath = this.store.getMainViewScenePath();
104
210
  if (!mainScenePath) return;
@@ -109,8 +215,61 @@ export class AppManager {
109
215
  }
110
216
  this.displayerWritableListener(!this.room?.isWritable);
111
217
  this.displayer.callbacks.on("onEnableWriteNowChanged", this.displayerWritableListener);
218
+ this._prevFocused = this.attributes.focus;
219
+ this.addRedoUndoListeners(this.attributes.focus);
112
220
  }
113
221
 
222
+ private disposePrevFocusViewRedoUndoListeners = (prevFocused: string | undefined) => {
223
+ if (prevFocused === undefined) {
224
+ this.mainView.callbacks.off("onCanRedoStepsUpdate", this.onCanRedoStepsUpdate);
225
+ this.mainView.callbacks.off("onCanUndoStepsUpdate", this.onCanRedoStepsUpdate);
226
+ } else {
227
+ const appProxy = this.appProxies.get(prevFocused);
228
+ if (appProxy) {
229
+ appProxy.view?.callbacks.off("onCanRedoStepsUpdate", this.onCanRedoStepsUpdate);
230
+ appProxy.view?.callbacks.off("onCanUndoStepsUpdate", this.onCanUndoStepsUpdate);
231
+ }
232
+ }
233
+ };
234
+
235
+ private addRedoUndoListeners = (focused: string | undefined) => {
236
+ if (focused === undefined) {
237
+ this.addViewCallbacks(
238
+ this.mainView,
239
+ this.onCanRedoStepsUpdate,
240
+ this.onCanUndoStepsUpdate
241
+ );
242
+ } else {
243
+ const focusApp = this.appProxies.get(focused);
244
+ if (focusApp && focusApp.view) {
245
+ this.addViewCallbacks(
246
+ focusApp.view,
247
+ this.onCanRedoStepsUpdate,
248
+ this.onCanUndoStepsUpdate
249
+ );
250
+ }
251
+ }
252
+ };
253
+
254
+ private addViewCallbacks = (
255
+ view: View,
256
+ redoListener: (steps: number) => void,
257
+ undoListener: (steps: number) => void
258
+ ) => {
259
+ redoListener(view.canRedoSteps);
260
+ undoListener(view.canUndoSteps);
261
+ view.callbacks.on("onCanRedoStepsUpdate", redoListener);
262
+ view.callbacks.on("onCanUndoStepsUpdate", undoListener);
263
+ };
264
+
265
+ private onCanRedoStepsUpdate = (steps: number) => {
266
+ callbacks.emit("canRedoStepsChange", steps);
267
+ };
268
+
269
+ private onCanUndoStepsUpdate = (steps: number) => {
270
+ callbacks.emit("canUndoStepsChange", steps);
271
+ };
272
+
114
273
  /**
115
274
  * 插件更新 attributes 时的回调
116
275
  *
@@ -126,19 +285,18 @@ export class AppManager {
126
285
  createdAt: apps[appId].createdAt,
127
286
  };
128
287
  });
129
- for (const { id } of sortBy(appsWithCreatedAt, "createdAt")) {
288
+ for (const { id } of orderBy(appsWithCreatedAt, "createdAt", "asc")) {
130
289
  if (!this.appProxies.has(id) && !this.appStatus.has(id)) {
131
290
  const app = apps[id];
132
291
 
133
- pRetry(
134
- async () => {
135
- this.appStatus.set(id, AppStatus.StartCreate);
136
- // 防御 appAttributes 有可能为 undefined 的情况,这里做一个重试
137
- const appAttributes = this.attributes[id];
138
- if (!appAttributes) {
139
- throw new Error("appAttributes is undefined");
140
- }
141
- await this.baseInsertApp(
292
+ this.appStatus.set(id, AppStatus.StartCreate);
293
+ try {
294
+ const appAttributes = this.attributes[id];
295
+ if (!appAttributes) {
296
+ throw new Error("appAttributes is undefined");
297
+ }
298
+ this.appCreateQueue.push(() => {
299
+ return this.baseInsertApp(
142
300
  {
143
301
  kind: app.kind,
144
302
  options: app.options,
@@ -147,13 +305,11 @@ export class AppManager {
147
305
  id,
148
306
  false
149
307
  );
150
- this.focusByAttributes(apps);
151
- },
152
- { retries: 3 }
153
- ).catch(err => {
154
- console.warn(`[WindowManager]: Insert App Error`, err);
155
- this.appStatus.delete(id);
156
- });
308
+ });
309
+ this.focusByAttributes(apps);
310
+ } catch (error) {
311
+ console.warn(`[WindowManager]: Insert App Error`, error);
312
+ }
157
313
  }
158
314
  }
159
315
  }
@@ -189,15 +345,19 @@ export class AppManager {
189
345
  mainView.disableCameraTransform = disableCameraTransform;
190
346
  mainView.divElement = divElement;
191
347
  if (!mainView.focusScenePath) {
192
- this.store.setMainViewFocusPath(mainView);
193
- }
194
- if (this.store.focus === undefined && mainView.mode !== ViewVisionMode.Writable) {
195
- this.viewManager.switchMainViewToWriter();
348
+ this.setMainViewFocusPath();
196
349
  }
197
- this.mainViewProxy.addMainViewListener();
198
350
  emitter.emit("mainViewMounted");
199
351
  }
200
352
 
353
+ public setMainViewFocusPath(scenePath?: string) {
354
+ const focusScenePath = scenePath || this.store.getMainViewScenePath();
355
+ if (focusScenePath) {
356
+ const view = setViewFocusScenePath(this.mainView, focusScenePath);
357
+ return view?.focusScenePath === focusScenePath;
358
+ }
359
+ }
360
+
201
361
  public async addApp(params: AddAppParams, isDynamicPPT: boolean): Promise<string | undefined> {
202
362
  log("addApp", params);
203
363
  const { appId, needFocus } = await this.beforeAddApp(params, isDynamicPPT);
@@ -273,17 +433,13 @@ export class AppManager {
273
433
  }
274
434
  });
275
435
  }
276
- if (state.roomMembers) {
277
- this.windowManger.cursorManager?.setRoomMembers(state.roomMembers);
278
- this.windowManger.cursorManager?.cleanMemberAttributes(state.roomMembers);
279
- }
280
436
  this.appProxies.forEach(appProxy => {
281
437
  appProxy.appEmitter.emit("roomStateChange", state);
282
438
  });
283
439
  emitter.emit("observerIdChange", this.displayer.observerId);
284
440
  };
285
441
 
286
- private displayerWritableListener = (isReadonly: boolean) => {
442
+ public displayerWritableListener = (isReadonly: boolean) => {
287
443
  const isWritable = !isReadonly;
288
444
  const isManualWritable =
289
445
  this.windowManger.readonly === undefined || this.windowManger.readonly === false;
@@ -296,41 +452,15 @@ export class AppManager {
296
452
  appProxy.emitAppIsWritableChange();
297
453
  });
298
454
  if (isWritable === true) {
299
- if (!this.store.focus) {
300
- this.mainViewProxy.switchViewModeToWriter();
301
- }
302
455
  this.mainView.disableCameraTransform = false;
456
+ if (this.room && this.room.disableSerialization === true) {
457
+ this.room.disableSerialization = false;
458
+ }
303
459
  } else {
304
460
  this.mainView.disableCameraTransform = true;
305
461
  }
306
462
  };
307
463
 
308
- private get eventName() {
309
- return isRoom(this.displayer) ? "onRoomStateChanged" : "onPlayerStateChanged";
310
- }
311
-
312
- public get attributes() {
313
- return this.windowManger.attributes;
314
- }
315
-
316
- public get canOperate() {
317
- return this.windowManger.canOperate;
318
- }
319
-
320
- public get room() {
321
- return isRoom(this.displayer) ? (this.displayer as Room) : undefined;
322
- }
323
-
324
- public get mainView() {
325
- return this.mainViewProxy.view;
326
- }
327
-
328
- public get focusApp() {
329
- if (this.store.focus) {
330
- return this.appProxies.get(this.store.focus);
331
- }
332
- }
333
-
334
464
  public safeSetAttributes(attributes: any) {
335
465
  this.windowManger.safeSetAttributes(attributes);
336
466
  }
@@ -342,37 +472,74 @@ export class AppManager {
342
472
  public async setMainViewScenePath(scenePath: string) {
343
473
  if (this.room) {
344
474
  const scenePathType = this.displayer.scenePathType(scenePath);
475
+ const sceneDir = parseSceneDir(scenePath);
476
+ if (sceneDir !== ROOT_DIR) {
477
+ throw new Error(`[WindowManager]: main view scenePath must in root dir "/"`);
478
+ }
345
479
  if (scenePathType === ScenePathType.None) {
346
480
  throw new Error(`[WindowManager]: ${scenePath} not valid scene`);
347
481
  } else if (scenePathType === ScenePathType.Page) {
348
482
  await this._setMainViewScenePath(scenePath);
349
483
  } else if (scenePathType === ScenePathType.Dir) {
350
484
  const validScenePath = makeValidScenePath(this.displayer, scenePath);
351
- await this._setMainViewScenePath(validScenePath);
485
+ if (validScenePath) {
486
+ await this._setMainViewScenePath(validScenePath);
487
+ }
352
488
  }
353
489
  }
354
490
  }
355
491
 
356
492
  private async _setMainViewScenePath(scenePath: string) {
357
- this.safeSetAttributes({ _mainScenePath: scenePath });
358
- await this.viewManager.switchMainViewToWriter();
359
- setScenePath(this.room, scenePath);
360
- this.store.setMainViewFocusPath(this.mainView);
361
- this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath: scenePath });
493
+ const success = this.setMainViewFocusPath(scenePath);
494
+ if (success) {
495
+ this.safeSetAttributes({ _mainScenePath: scenePath });
496
+ this.store.setMainViewFocusPath(this.mainView);
497
+ this.updateSceneIndex();
498
+ this.dispatchSetMainViewScenePath(scenePath);
499
+ }
362
500
  }
363
501
 
502
+ private updateSceneIndex = () => {
503
+ const scenePath = this.store.getMainViewScenePath() as string;
504
+ const sceneDir = parseSceneDir(scenePath);
505
+ const scenes = entireScenes(this.displayer)[sceneDir];
506
+ if (scenes.length) {
507
+ // "/ppt3/1" -> "1"
508
+ const pageName = scenePath.replace(sceneDir, "").replace("/", "");
509
+ const index = scenes.findIndex(scene => scene.name === pageName);
510
+ if (isInteger(index) && index >= 0) {
511
+ this.safeSetAttributes({ _mainSceneIndex: index });
512
+ }
513
+ }
514
+ };
515
+
364
516
  public async setMainViewSceneIndex(index: number) {
365
517
  if (this.room) {
366
- this.safeSetAttributes({ _mainSceneIndex: index });
367
- await this.viewManager.switchMainViewToWriter();
368
- this.room.setSceneIndex(index);
369
- const nextScenePath = this.room.state.sceneState.scenePath;
370
- this.store.setMainViewScenePath(nextScenePath);
371
- this.store.setMainViewFocusPath(this.mainView);
372
- this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath });
518
+ if (this.store.getMainViewSceneIndex() === index) return;
519
+ const mainViewScenePath = this.store.getMainViewScenePath() as string;
520
+ if (mainViewScenePath) {
521
+ const sceneDir = parseSceneDir(mainViewScenePath);
522
+ const scenePath = makeValidScenePath(this.displayer, sceneDir, index);
523
+ if (scenePath) {
524
+ const success = this.setMainViewFocusPath(scenePath);
525
+ if (success) {
526
+ this.store.setMainViewScenePath(scenePath);
527
+ this.safeSetAttributes({ _mainSceneIndex: index });
528
+ this.dispatchSetMainViewScenePath(scenePath);
529
+ }
530
+ } else {
531
+ throw new Error(`[WindowManager]: ${sceneDir}: ${index} not valid index`);
532
+ }
533
+ }
373
534
  }
374
535
  }
375
536
 
537
+ private dispatchSetMainViewScenePath(scenePath: string): void {
538
+ this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath: scenePath });
539
+ // 兼容 15 的 SDK, 需要 room 的当前 ScenePath
540
+ setScenePath(this.room, scenePath);
541
+ }
542
+
376
543
  public getAppInitPath(appId: string): string | undefined {
377
544
  const attrs = this.store.getAppAttributes(appId);
378
545
  if (attrs) {
@@ -440,6 +607,7 @@ export class AppManager {
440
607
  const reconnected = appProxies.map(appProxy => {
441
608
  return appProxy.onReconnected();
442
609
  });
610
+ this.mainViewProxy.onReconnect();
443
611
  await Promise.all(reconnected);
444
612
  }
445
613
 
@@ -456,6 +624,11 @@ export class AppManager {
456
624
  });
457
625
  }
458
626
 
627
+ public findMemberByUid = (uid: string) => {
628
+ const roomMembers = this.room?.state.roomMembers;
629
+ return roomMembers?.find(member => member.payload?.uid === uid);
630
+ };
631
+
459
632
  public destroy() {
460
633
  this.displayer.callbacks.off(this.eventName, this.displayerStateListener);
461
634
  this.displayer.callbacks.off("onEnableWriteNowChanged", this.displayerWritableListener);
@@ -472,5 +645,10 @@ export class AppManager {
472
645
  this.refresher?.destroy();
473
646
  this.mainViewProxy.destroy();
474
647
  callbacks.clearListeners();
648
+ this.callbacksNode?.dispose();
649
+ this.appCreateQueue.destroy();
650
+ this.disposePrevFocusViewRedoUndoListeners(this._prevFocused);
651
+ this._prevFocused = undefined;
652
+ this._prevSceneIndex = undefined;
475
653
  }
476
654
  }