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

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 +6839 -10495
  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 +66 -43
  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 +116 -75
  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
@@ -7,17 +7,17 @@ import {
7
7
  reaction,
8
8
  unlistenDisposed,
9
9
  unlistenUpdated,
10
- toJS,
10
+ toJS
11
11
  } from "white-web-sdk";
12
12
  import type {
13
13
  Room,
14
14
  SceneDefinition,
15
15
  View,
16
- EventListener as WhiteEventListener
16
+ EventListener as WhiteEventListener,
17
+ Player
17
18
  } from "white-web-sdk";
18
19
  import type { ReadonlyTeleBox } from "@netless/telebox-insider";
19
20
  import type Emittery from "emittery";
20
- import type { BoxManager } from "../BoxManager";
21
21
  import type { AppEmitterEvent, Member } from "../index";
22
22
  import type { AppManager } from "../AppManager";
23
23
  import type { AppProxy } from "./AppProxy";
@@ -29,8 +29,12 @@ import type {
29
29
  import { WhiteBoardView } from "./WhiteboardView";
30
30
  import { findMemberByUid } from "../Helper";
31
31
  import { MAX_PAGE_SIZE } from "../constants";
32
- import { putScenes } from "../Utils/Common";
33
- import { isNumber } from "lodash";
32
+ import { isBoolean, isNumber } from "lodash";
33
+
34
+ export type CreateWhiteBoardViewParams = {
35
+ size?: number;
36
+ syncCamera?: boolean;
37
+ }
34
38
 
35
39
  export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOptions = any> {
36
40
  public readonly emitter: Emittery<AppEmitterEvent<TAttributes>>;
@@ -49,11 +53,11 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
49
53
  private store = this.manager.store;
50
54
  public readonly isAddApp: boolean;
51
55
  public readonly isReplay = this.manager.isReplay;
52
- private whiteBoardView?: WhiteBoardView;
56
+ public whiteBoardView?: WhiteBoardView;
57
+ public _viewWrapper?: HTMLElement;
53
58
 
54
59
  constructor(
55
60
  private manager: AppManager,
56
- private boxManager: BoxManager,
57
61
  public appId: string,
58
62
  private appProxy: AppProxy,
59
63
  private appOptions?: TAppOptions | (() => TAppOptions)
@@ -62,9 +66,13 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
62
66
  this.isAddApp = appProxy.isAddApp;
63
67
  }
64
68
 
65
- public get displayer(){
69
+ public get displayer() {
66
70
  return this.manager.displayer;
67
- };
71
+ }
72
+
73
+ public get destroyed() {
74
+ return this.appProxy.status === "destroyed";
75
+ }
68
76
 
69
77
  /** @deprecated Use context.storage.state instead. */
70
78
  public getAttributes = (): TAttributes | undefined => {
@@ -84,7 +92,16 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
84
92
  return this.appProxy.view;
85
93
  };
86
94
 
87
- public createWhiteBoardView = (size?: number): WhiteBoardView => {
95
+ public get now(): number {
96
+ if (this.isReplay) {
97
+ const player = this.displayer as Player;
98
+ return player.beginTimestamp + player.progressTime;
99
+ } else {
100
+ return (this.displayer as Room).calibrationTimestamp;
101
+ }
102
+ }
103
+
104
+ public createWhiteBoardView = (params?: CreateWhiteBoardViewParams): WhiteBoardView => {
88
105
  if (this.whiteBoardView) {
89
106
  return this.whiteBoardView;
90
107
  }
@@ -92,21 +109,39 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
92
109
  if (!view) {
93
110
  view = this.appProxy.createAppDir();
94
111
  }
112
+ if (params) {
113
+ if (isBoolean(params.syncCamera)) {
114
+ this.appProxy.syncCamera$.setValue(params.syncCamera);
115
+ }
116
+ }
95
117
  const viewWrapper = document.createElement("div");
118
+ this._viewWrapper = viewWrapper;
96
119
  viewWrapper.className = "window-manager-view-wrapper";
97
- this.box.$content.parentElement?.appendChild(viewWrapper);
98
- const removeViewWrapper = () => {
99
- this.box.$content.parentElement?.removeChild(viewWrapper);
100
- }
120
+ this.box.$main.appendChild(viewWrapper);
101
121
  view.divElement = viewWrapper;
122
+ this.appProxy.fireMemberStateChange();
102
123
  if (this.isAddApp) {
103
- this.initPageSize(size);
124
+ this.ensurePageSize(params?.size);
104
125
  }
105
- this.whiteBoardView = new WhiteBoardView(this, this.appProxy, removeViewWrapper);
126
+ this.whiteBoardView = new WhiteBoardView(view, this, this.appProxy, this.ensurePageSize);
127
+ this.appProxy.sideEffectManager.add(() => [
128
+ this.box._stageRect$.subscribe(rect => {
129
+ viewWrapper.style.left = `${rect.x}px`;
130
+ viewWrapper.style.top = `${rect.y}px`;
131
+ viewWrapper.style.width = `${rect.width}px`;
132
+ viewWrapper.style.height = `${rect.height}px`;
133
+ }),
134
+ () => {
135
+ return () => {
136
+ this.whiteBoardView = undefined;
137
+ }
138
+ }
139
+ ]);
140
+ this.appProxy.whiteBoardViewCreated$.setValue(true);
106
141
  return this.whiteBoardView;
107
142
  }
108
143
 
109
- private initPageSize = (size?: number) => {
144
+ private ensurePageSize = (size?: number) => {
110
145
  if (!isNumber(size)) return;
111
146
  if (!this.appProxy.scenePath) return;
112
147
  if (this.appProxy.pageState.length >= size) return;
@@ -114,25 +149,22 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
114
149
  throw Error(`[WindowManager]: size ${size} muse be in range [1, ${MAX_PAGE_SIZE}]`);
115
150
  }
116
151
  const needInsert = size - this.appProxy.pageState.length;
117
- const startPageNumber = this.appProxy.pageState.length;
118
- const scenes = new Array(needInsert).fill({}).map((_, index) => {
119
- return { name: `${startPageNumber + index + 1}` };
120
- });
121
- putScenes(this.room, this.appProxy.scenePath, scenes);
152
+ const scenes = new Array(needInsert).fill({});
153
+ this.room?.putScenes(this.appProxy.scenePath, scenes);
122
154
  }
123
155
 
124
156
  public getInitScenePath = () => {
125
- return this.manager.getAppInitPath(this.appId);
157
+ return this.appProxy.scenePath;
126
158
  };
127
159
 
128
160
  /** Get App writable status. */
129
161
  public get isWritable(): boolean {
130
- return this.manager.canOperate;
162
+ return this.manager.canOperate && !this.destroyed;
131
163
  };
132
164
 
133
165
  /** Get the App Window UI box. */
134
166
  public get box(): ReadonlyTeleBox {
135
- const box = this.boxManager.getBox(this.appId);
167
+ const box = this.appProxy.box$.value;
136
168
  if (box) {
137
169
  return box;
138
170
  } else {
@@ -144,14 +176,15 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
144
176
  return this.manager.room;
145
177
  };
146
178
 
147
- public get members() {
148
- return this.manager.members;
179
+ public get members(): Member[] {
180
+ return this.manager.members$.value;
149
181
  }
150
182
 
151
- public get memberState(): Member {
183
+ //** currentMember is undefined in read-only and replay mode. */
184
+ public get currentMember(): Member | undefined {
152
185
  const self = findMemberByUid(this.room, this.manager.uid);
153
186
  if (!self) {
154
- throw new Error(`Member ${this.manager.uid} not found.`);
187
+ return undefined;
155
188
  }
156
189
  return {
157
190
  uid: this.manager.uid,
@@ -3,13 +3,13 @@ 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 { AppViewSync } from "./AppViewSync";
6
+ import { ViewSync } from "../View/ViewSync"
7
7
  import { autorun, reaction, toJS } from "white-web-sdk";
8
8
  import { boxEmitter } from "../BoxEmitter";
9
- import { BoxManagerNotFoundError } from "../Utils/error";
9
+ import { BoxManagerNotInitializeError } from "../Utils/error";
10
10
  import { calculateNextIndex } from "../Page";
11
- import { combine, Val } from "value-enhancer";
12
- import { debounce, get } from "lodash";
11
+ import { combine, Val, ValManager } from "value-enhancer";
12
+ import { debounce, get, isEqual, isUndefined, omitBy } from "lodash";
13
13
  import { emitter } from "../InternalEmitter";
14
14
  import { Fields } from "../AttributesDelegate";
15
15
  import { log } from "../Utils/log";
@@ -25,16 +25,17 @@ import {
25
25
  } from "../Utils/Common";
26
26
  import type {
27
27
  AppEmitterEvent,
28
- AppInitState,
29
28
  BaseInsertParams,
30
29
  setAppOptions,
31
30
  AppListenerKeys,
32
31
  } from "../index";
33
- import type { SceneState, View, SceneDefinition, Camera } from "white-web-sdk";
32
+ import type { SceneState, View, SceneDefinition, MemberState} from "white-web-sdk";
34
33
  import type { AppManager } from "../AppManager";
35
34
  import type { NetlessApp } from "../typings";
36
- import type { ReadonlyTeleBox } from "@netless/telebox-insider";
35
+ import type { ReadonlyTeleBox, TeleBox, TeleBoxRect } from "@netless/telebox-insider";
37
36
  import type { PageRemoveService, PageState } from "../Page";
37
+ import type { AppState } from "./type";
38
+ import { callbacks } from "../callback";
38
39
 
39
40
  export type AppEmitter = Emittery<AppEmitterEvent>;
40
41
 
@@ -54,23 +55,25 @@ export class AppProxy implements PageRemoveService {
54
55
  public uid = this.manager.uid;
55
56
 
56
57
  public isAddApp: boolean;
57
- private status: "normal" | "destroyed" = "normal";
58
+ public status: "normal" | "destroyed" = "normal";
58
59
  private stateKey: string;
59
60
  public _pageState: AppPageStateImpl;
60
- private _prevFullPath: string | undefined;
61
61
 
62
- public appResult?: NetlessApp<any>;
63
- public appContext?: AppContext<any, any>;
62
+ public appResult?: NetlessApp;
63
+ public appContext?: AppContext;
64
64
 
65
- private sideEffectManager = new SideEffectManager();
65
+ public sideEffectManager = new SideEffectManager();
66
+ private valManager = new ValManager();
66
67
 
67
- public camera$ = new Val<ICamera | undefined>(undefined);
68
- public size$ = new Val<ISize | undefined>(undefined);
68
+ private fullPath$ = this.valManager.attach(new Val<string | undefined>(undefined));
69
+ private viewSync?: ViewSync;
69
70
 
70
- private appViewSync?: AppViewSync;
71
-
72
- public box$ = new Val<ReadonlyTeleBox | undefined>(undefined);
73
- public view$ = new Val<View | undefined>(undefined);
71
+ public camera$ = this.valManager.attach(new Val<ICamera | undefined>(undefined));
72
+ public size$ = this.valManager.attach(new Val<ISize | undefined>(undefined));
73
+ public box$ = this.valManager.attach(new Val<ReadonlyTeleBox | undefined>(undefined));
74
+ public view$ = this.valManager.attach(new Val<View | undefined>(undefined));
75
+ public syncCamera$ = this.valManager.attach(new Val<boolean>(true));
76
+ public whiteBoardViewCreated$ = this.valManager.attach(new Val<boolean>(false));
74
77
 
75
78
  constructor(
76
79
  private params: BaseInsertParams,
@@ -103,44 +106,107 @@ export class AppProxy implements PageRemoveService {
103
106
  notifyPageStateChange: this.notifyPageStateChange,
104
107
  });
105
108
  this.sideEffectManager.add(() => () => this._pageState.destroy());
106
- this.sideEffectManager.add(() =>
107
- emitter.on("roomMembersChange", members => {
108
- this.appEmitter.emit("roomMembersChange", members);
109
- })
110
- );
111
109
  this.camera$.setValue(toJS(this.appAttributes.camera));
112
110
  this.size$.setValue(toJS(this.appAttributes.size));
113
- this.sideEffectManager.add(() => {
114
- return this.manager.refresher.add(`${this.id}-camera`, () => {
115
- return reaction(
116
- () => this.appAttributes?.camera,
117
- camera => {
118
- if (camera && camera.id !== this.uid) {
119
- this.camera$.setValue(toJS(camera));
120
- }
111
+ this.addCameraReaction();
112
+ this.addSizeReaction();
113
+ this.sideEffectManager.add(() =>
114
+ emitter.on("memberStateChange", this.onMemberStateChange)
115
+ );
116
+ this.sideEffectManager.add(() => [
117
+ this.syncCamera$.reaction(syncCamera => {
118
+ if (!syncCamera) {
119
+ if (this.viewSync) {
120
+ this.viewSync.destroy();
121
+ this.viewSync = undefined;
122
+ this.sideEffectManager.flush("camera");
123
+ this.sideEffectManager.flush("size");
121
124
  }
122
- );
123
- });
124
- });
125
- this.sideEffectManager.add(() => {
126
- return this.manager.refresher.add(`${this.id}-size`, () => {
127
- return reaction(
128
- () => this.appAttributes?.size,
129
- size => {
130
- if (size && size.id !== this.uid) {
131
- this.size$.setValue(toJS(size));
125
+ }
126
+ }),
127
+ this.whiteBoardViewCreated$.reaction(created => {
128
+ if (created && this.box) {
129
+ if (!this.syncCamera$.value) return;
130
+ combine([this.box$, this.view$]).subscribe(([box, view]) => {
131
+ if (box && view) {
132
+ if (!this.camera$.value) {
133
+ this.storeCamera({
134
+ centerX: null,
135
+ centerY: null,
136
+ scale: 1,
137
+ id: this.uid,
138
+ });
139
+ this.camera$.setValue(toJS(this.appAttributes.camera));
140
+ }
141
+ if (!this.size$.value && box.stageRect) {
142
+ const initialRect = this.computedInitialRect(box.stageRect);
143
+ const width = initialRect?.width || box.stageRect.width;
144
+ const height = initialRect?.height || box.stageRect.height;
145
+ this.storeSize({
146
+ id: this.uid,
147
+ width,
148
+ height,
149
+ });
150
+ this.size$.setValue(toJS(this.appAttributes.size));
151
+ }
152
+ this.viewSync = new ViewSync({
153
+ uid: this.uid,
154
+ view$: this.view$,
155
+ camera$: this.camera$,
156
+ size$: this.size$,
157
+ stageRect$: box._stageRect$,
158
+ storeCamera: this.storeCamera,
159
+ storeSize: this.storeSize
160
+ });
161
+ this.sideEffectManager.add(() => () => this.viewSync?.destroy());
162
+ this.whiteBoardViewCreated$.destroy();
132
163
  }
133
- }
134
- );
135
- });
136
- });
137
- combine([this.box$, this.view$]).subscribe(([box, view]) => {
138
- if (box && view) {
139
- const appViewSync = new AppViewSync(this);
140
- this.appViewSync = appViewSync;
141
- this.sideEffectManager.add(() => () => appViewSync.destroy());
164
+ })
165
+ }
166
+ }),
167
+ this.manager.members$.reaction(members => {
168
+ this.appEmitter.emit("roomMembersChange", members);
169
+ }),
170
+ ]);
171
+ }
172
+
173
+ public fireMemberStateChange = () => {
174
+ if (this.manager.room) {
175
+ this.onMemberStateChange(this.manager.room.state.memberState);
176
+ }
177
+ }
178
+
179
+ private onMemberStateChange = (memberState: MemberState) => {
180
+ // clicker 教具把事件穿透给下层
181
+ const needPointerEventsNone = memberState.currentApplianceName === "clicker";
182
+ if (needPointerEventsNone) {
183
+ if (this.appContext?._viewWrapper) {
184
+ this.appContext._viewWrapper.style.pointerEvents = "none";
142
185
  }
143
- });
186
+ } else {
187
+ if (this.appContext?._viewWrapper) {
188
+ this.appContext._viewWrapper.style.pointerEvents = "auto";
189
+ }
190
+ }
191
+ }
192
+
193
+ private computedInitialRect = (boxRect: TeleBoxRect) => {
194
+ const managerRect = this.manager.boxManager?.stageRect;
195
+ if (managerRect) {
196
+ const { width, height } = managerRect;
197
+ const boxRatio = boxRect.height / boxRect.width;
198
+ if (height < 480) {
199
+ return {
200
+ width: 480 / boxRatio,
201
+ height: 480,
202
+ };
203
+ } else {
204
+ return {
205
+ width: width * 0.65,
206
+ height: height * 0.65,
207
+ };
208
+ }
209
+ }
144
210
  }
145
211
 
146
212
  public createAppDir() {
@@ -170,7 +236,7 @@ export class AppProxy implements PageRemoveService {
170
236
  }
171
237
 
172
238
  public get view(): View | undefined {
173
- return this.manager.viewManager.getView(this.id);
239
+ return this.view$.value;
174
240
  }
175
241
 
176
242
  public get viewIndex(): number | undefined {
@@ -246,13 +312,13 @@ export class AppProxy implements PageRemoveService {
246
312
  ) {
247
313
  log("setupApp", appId, app, options);
248
314
  if (!this.boxManager) {
249
- throw new BoxManagerNotFoundError();
315
+ throw new BoxManagerNotInitializeError();
250
316
  }
251
- const context = new AppContext(this.manager, this.boxManager, appId, this, appOptions);
317
+ const context = new AppContext(this.manager, appId, this, appOptions);
252
318
  this.appContext = context;
253
319
  try {
254
320
  emitter.once(`${appId}${Events.WindowCreated}` as any).then(async () => {
255
- let boxInitState: AppInitState | undefined;
321
+ let boxInitState: AppState | undefined;
256
322
  if (!skipUpdate) {
257
323
  boxInitState = this.getAppInitState(appId);
258
324
  this.boxManager?.updateBoxState(boxInitState);
@@ -266,6 +332,9 @@ export class AppProxy implements PageRemoveService {
266
332
  this.appResult = result;
267
333
  appRegister.notifyApp(this.kind, "created", { appId, result });
268
334
  this.fixMobileSize();
335
+ if (this.isAddApp) {
336
+ this.setupDone();
337
+ }
269
338
  }, SETUP_APP_DELAY);
270
339
  });
271
340
  const box = this.boxManager?.createBox({
@@ -274,10 +343,18 @@ export class AppProxy implements PageRemoveService {
274
343
  options,
275
344
  canOperate: this.manager.canOperate,
276
345
  smartPosition: this.isAddApp,
277
- });
346
+ }) as TeleBox;
347
+ const registerParams = appRegister.registered.get(this.kind);
348
+ if (registerParams?.contentStyles) {
349
+ box?.mountUserStyles(registerParams.contentStyles);
350
+ }
278
351
  this.box$.setValue(box);
279
352
  if (this.isAddApp && this.box) {
280
353
  this.store.updateAppState(appId, AppAttributes.ZIndex, this.box.zIndex);
354
+ this.store.updateAppState(appId, AppAttributes.Size, {
355
+ width: this.box.intrinsicWidth,
356
+ height: this.box.intrinsicHeight,
357
+ });
281
358
  this.boxManager.focusBox({ appId }, false);
282
359
  }
283
360
  } catch (error: any) {
@@ -290,12 +367,14 @@ export class AppProxy implements PageRemoveService {
290
367
  private fixMobileSize() {
291
368
  const box = this.boxManager?.getBox(this.id);
292
369
  if (box) {
293
- this.boxManager?.resizeBox({
294
- appId: this.id,
295
- width: box.intrinsicWidth + 0.001,
296
- height: box.intrinsicHeight + 0.001,
297
- skipUpdate: true,
298
- });
370
+ if (!box.minimized) {
371
+ this.boxManager?.resizeBox({
372
+ appId: this.id,
373
+ width: box.intrinsicWidth + 0.001,
374
+ height: box.intrinsicHeight + 0.001,
375
+ skipUpdate: true,
376
+ });
377
+ }
299
378
  }
300
379
  }
301
380
 
@@ -340,30 +419,18 @@ export class AppProxy implements PageRemoveService {
340
419
  }
341
420
  }
342
421
 
343
- public getAppInitState = (id: string) => {
422
+ public getAppInitState = (id: string): AppState | undefined => {
344
423
  const attrs = this.store.getAppState(id);
345
424
  if (!attrs) return;
346
- const position = attrs?.[AppAttributes.Position];
347
425
  const focus = this.store.focus;
348
- const size = attrs?.[AppAttributes.Size];
349
- const sceneIndex = attrs?.[AppAttributes.SceneIndex];
350
426
  const maximized = this.attributes?.["maximized"];
351
427
  const minimized = this.attributes?.["minimized"];
352
- const zIndex = attrs?.zIndex;
353
- let payload = { maximized, minimized, zIndex } as AppInitState;
354
- if (position) {
355
- payload = { ...payload, id: id, x: position.x, y: position.y };
356
- }
428
+ let payload = { maximized, minimized, id } as AppState;
429
+ const state = omitBy(attrs, isUndefined);
357
430
  if (focus === id) {
358
431
  payload = { ...payload, focus: true };
359
432
  }
360
- if (size) {
361
- payload = { ...payload, width: size.width, height: size.height };
362
- }
363
- if (sceneIndex) {
364
- payload = { ...payload, sceneIndex };
365
- }
366
- return payload;
433
+ return Object.assign(payload, state);;
367
434
  };
368
435
 
369
436
  public emitAppSceneStateChange(sceneState: SceneState) {
@@ -420,32 +487,34 @@ export class AppProxy implements PageRemoveService {
420
487
  }
421
488
 
422
489
  private appAttributesUpdateListener = (appId: string) => {
423
- this.manager.refresher?.add(appId, () => {
424
- return autorun(() => {
425
- const attrs = this.manager.attributes[appId];
426
- if (attrs) {
427
- this.appEmitter.emit("attributesUpdate", attrs);
428
- }
429
- });
430
- });
431
- this.manager.refresher?.add(this.stateKey, () => {
432
- return autorun(() => {
433
- const appState = this.appAttributes?.state;
434
- if (appState?.zIndex > 0 && appState.zIndex !== this.box?.zIndex) {
435
- this.boxManager?.setZIndex(appId, appState.zIndex);
436
- }
437
- });
438
- });
439
- this.manager.refresher?.add(`${appId}-fullPath`, () => {
440
- return autorun(() => {
441
- const fullPath = this.appAttributes?.fullPath;
442
- this.setFocusScenePathHandler(fullPath);
443
- if (this._prevFullPath !== fullPath) {
444
- this.notifyPageStateChange();
445
- this._prevFullPath = fullPath;
446
- }
447
- });
448
- });
490
+ this.sideEffectManager.add(() => [
491
+ this.manager.refresher.add(appId, () => {
492
+ return autorun(() => {
493
+ const attrs = this.manager.attributes[appId];
494
+ if (attrs) {
495
+ this.appEmitter.emit("attributesUpdate", attrs);
496
+ }
497
+ });
498
+ }),
499
+ this.manager.refresher.add(this.stateKey, () => {
500
+ return autorun(() => {
501
+ const appState = this.appAttributes?.state;
502
+ if (appState?.zIndex > 0 && appState.zIndex !== this.box?.zIndex) {
503
+ this.boxManager?.setZIndex(appId, appState.zIndex);
504
+ }
505
+ });
506
+ }),
507
+ this.manager.refresher.add(`${appId}-fullPath`, () => {
508
+ return autorun(() => {
509
+ const fullPath = this.appAttributes?.fullPath;
510
+ this.setFocusScenePathHandler(fullPath);
511
+ if (this.fullPath$.value !== fullPath) {
512
+ this.notifyPageStateChange();
513
+ this.fullPath$.setValue(fullPath);
514
+ }
515
+ });
516
+ }),
517
+ ]);
449
518
  };
450
519
 
451
520
  private setFocusScenePathHandler = debounce((fullPath: string | undefined) => {
@@ -463,6 +532,7 @@ export class AppProxy implements PageRemoveService {
463
532
  }
464
533
 
465
534
  public setViewFocusScenePath() {
535
+ if (this.status === "destroyed") return;
466
536
  const fullPath = this.getFullScenePath();
467
537
  if (fullPath && this.view) {
468
538
  setViewFocusScenePath(this.view, fullPath);
@@ -522,6 +592,7 @@ export class AppProxy implements PageRemoveService {
522
592
  const fullPath = this._pageState.getFullPath(index);
523
593
  if (fullPath) {
524
594
  this.setFullPath(fullPath);
595
+ setScenePath(this.manager.room, fullPath);
525
596
  }
526
597
  }
527
598
  }
@@ -534,12 +605,22 @@ export class AppProxy implements PageRemoveService {
534
605
  this.store.updateAppAttributes(this.id, Fields.Size, size);
535
606
  };
536
607
 
537
- public moveCamera = (camera: Camera) => {
608
+ public updateSize = (width: number, height: number) => {
609
+ const iSize = {
610
+ id: this.manager.uid,
611
+ width, height
612
+ }
613
+ this.store.updateAppAttributes(this.id, Fields.Size, iSize);
614
+ this.size$.setValue(iSize);
615
+ }
616
+
617
+ public moveCamera = (camera: Partial<ICamera>) => {
538
618
  if (!this.camera$.value) {
539
619
  return;
540
620
  }
541
- const nextCamera = { ...this.camera$.value, ...camera };
621
+ const nextCamera = { ...this.camera$.value, ...camera, id: this.uid };
542
622
  this.storeCamera(nextCamera);
623
+ this.camera$.setValue(nextCamera);
543
624
  };
544
625
 
545
626
  public async destroy(
@@ -552,6 +633,7 @@ export class AppProxy implements PageRemoveService {
552
633
  this.status = "destroyed";
553
634
  try {
554
635
  await appRegister.notifyApp(this.kind, "destroy", { appId: this.id });
636
+ callbacks.emit("appClose", { appId: this.id, kind: this.kind, error });
555
637
  await this.appEmitter.emit("destroy", { error });
556
638
  } catch (error) {
557
639
  console.error("[WindowManager]: notifyApp error", error.message, error.stack);
@@ -572,13 +654,53 @@ export class AppProxy implements PageRemoveService {
572
654
 
573
655
  this.viewManager.destroyView(this.id);
574
656
  this.manager.appStatus.delete(this.id);
575
- this.manager.refresher?.remove(this.id);
576
- this.manager.refresher?.remove(this.stateKey);
577
- this.manager.refresher?.remove(`${this.id}-fullPath`);
578
- this._prevFullPath = undefined;
579
- this.camera$.destroy();
580
- this.size$.destroy();
581
- this.box$.destroy();
657
+ this.valManager.destroy();
658
+ }
659
+
660
+ private addCameraReaction = () => {
661
+ this.sideEffectManager.add(() =>
662
+ this.manager.refresher.add(`${this.id}-camera`, () =>
663
+ reaction(
664
+ () => this.appAttributes?.camera,
665
+ camera => {
666
+ if (camera) {
667
+ const rawCamera = toJS(camera);
668
+ if (!isEqual(rawCamera, this.camera$.value)) {
669
+ this.camera$.setValue(rawCamera);
670
+ }
671
+ }
672
+ }
673
+ )
674
+ )
675
+ , "camera");
676
+ }
677
+
678
+ private addSizeReaction = () => {
679
+ this.sideEffectManager.add(() =>
680
+ this.manager.refresher.add(`${this.id}-size`, () =>
681
+ reaction(
682
+ () => this.appAttributes?.size,
683
+ size => {
684
+ if (size) {
685
+ const rawSize = toJS(size);
686
+ if (!isEqual(rawSize, this.size$.value)) {
687
+ this.size$.setValue(rawSize);
688
+ }
689
+ }
690
+ }
691
+ )
692
+ )
693
+ , "size");
694
+ }
695
+
696
+ public onFocus = () => {
697
+ this.setScenePath();
698
+ }
699
+
700
+ // 异步值设置完成通知其他端创建 app
701
+ private setupDone = () => {
702
+ this.store.updateAppAttributes(this.id, "setup", true);
703
+ this.manager.dispatchInternalEvent(Events.InvokeAttributesUpdateCallback);
582
704
  }
583
705
 
584
706
  public close(): Promise<void> {