@netless/window-manager 0.4.30 → 0.4.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/AppManager.ts CHANGED
@@ -4,6 +4,8 @@ import { AppListeners } from "./AppListener";
4
4
  import { AppProxy } from "./App";
5
5
  import { appRegister } from "./Register";
6
6
  import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
7
+ import { boxEmitter } from "./BoxEmitter";
8
+ import { calculateNextIndex } from "./Page";
7
9
  import { callbacks } from "./callback";
8
10
  import { debounce, get, isInteger, orderBy } from "lodash";
9
11
  import { emitter } from "./InternalEmitter";
@@ -16,7 +18,7 @@ import { RedoUndo } from "./RedoUndo";
16
18
  import { SideEffectManager } from "side-effect-manager";
17
19
  import { ViewManager } from "./View/ViewManager";
18
20
  import type { SyncRegisterAppPayload } from "./Register";
19
- import type { EmitterEvent , RemoveSceneParams } from "./InternalEmitter";
21
+ import type { RemoveSceneParams } from "./InternalEmitter";
20
22
  import {
21
23
  entireScenes,
22
24
  genAppId,
@@ -37,7 +39,14 @@ import type {
37
39
  SceneState,
38
40
  } from "white-web-sdk";
39
41
  import type { AddAppParams, BaseInsertParams, TeleBoxRect } from "./index";
40
- import { calculateNextIndex } from "./Page";
42
+ import type {
43
+ BoxClosePayload,
44
+ BoxFocusPayload,
45
+ BoxMovePayload,
46
+ BoxResizePayload,
47
+ BoxStateChangePayload,
48
+ } from "./BoxEmitter";
49
+
41
50
 
42
51
  export class AppManager {
43
52
  public displayer: Displayer;
@@ -202,27 +211,30 @@ export class AppManager {
202
211
  const scene = this.callbacksNode?.scenes[index];
203
212
  setTimeout(() => {
204
213
  if (scene) {
205
- removeScenes(this.room, `${ROOT_DIR}${scene}`, index)
214
+ removeScenes(this.room, `${ROOT_DIR}${scene}`, index);
206
215
  }
207
216
  }, 100);
208
217
  return new Promise<boolean>((resolve, reject) => {
209
- emitter.once("rootDirSceneRemoved").then(name => {
210
- if (name === scene) {
211
- resolve(true);
212
- }
213
- }).catch(e => {
214
- console.log(`[WindowManager]: removePage error: ${e}`);
215
- reject(false);
216
- });
218
+ emitter
219
+ .once("rootDirSceneRemoved")
220
+ .then(name => {
221
+ if (name === scene) {
222
+ resolve(true);
223
+ }
224
+ })
225
+ .catch(e => {
226
+ console.log(`[WindowManager]: removePage error: ${e}`);
227
+ reject(false);
228
+ });
217
229
  });
218
- }
230
+ };
219
231
 
220
232
  public setSceneIndexWithoutSync = (index: number) => {
221
233
  const sceneName = this.callbacksNode?.scenes[index];
222
234
  if (sceneName) {
223
235
  this.mainViewProxy.setFocusScenePath(`${ROOT_DIR}${sceneName}`);
224
236
  }
225
- }
237
+ };
226
238
 
227
239
  private onSceneChange = (node: ScenesCallbacksNode) => {
228
240
  this.mainViewScenesLength = node.scenes.length;
@@ -299,7 +311,11 @@ export class AppManager {
299
311
  private async onCreated() {
300
312
  await this.attributesUpdateCallback(this.attributes.apps);
301
313
  emitter.emit("updateManagerRect");
302
- emitter.onAny(this.boxEventListener);
314
+ boxEmitter.on("move", this.onBoxMove);
315
+ boxEmitter.on("resize", this.onBoxResize);
316
+ boxEmitter.on("focus", this.onBoxFocus);
317
+ boxEmitter.on("close", this.onBoxClose);
318
+ boxEmitter.on("boxStateChange", this.onBoxStateChange);
303
319
 
304
320
  this.addAppsChangeListener();
305
321
  this.addAppCloseListener();
@@ -352,6 +368,39 @@ export class AppManager {
352
368
  });
353
369
  }
354
370
 
371
+ private onBoxMove = (payload: BoxMovePayload) => {
372
+ this.dispatchInternalEvent(Events.AppMove, payload);
373
+ this.store.updateAppState(payload.appId, AppAttributes.Position, {
374
+ x: payload.x,
375
+ y: payload.y,
376
+ });
377
+ };
378
+
379
+ private onBoxResize = (payload: BoxResizePayload) => {
380
+ if (payload.width && payload.height) {
381
+ this.dispatchInternalEvent(Events.AppResize, payload);
382
+ this.store.updateAppState(payload.appId, AppAttributes.Size, {
383
+ width: payload.width,
384
+ height: payload.height,
385
+ });
386
+ }
387
+ };
388
+
389
+ private onBoxFocus = (payload: BoxFocusPayload) => {
390
+ this.windowManger.safeSetAttributes({ focus: payload.appId });
391
+ };
392
+
393
+ private onBoxClose = (payload: BoxClosePayload) => {
394
+ const appProxy = this.appProxies.get(payload.appId);
395
+ if (appProxy) {
396
+ appProxy.destroy(false, true, true, payload.error);
397
+ }
398
+ };
399
+
400
+ private onBoxStateChange = (payload: BoxStateChangePayload) => {
401
+ this.dispatchInternalEvent(Events.AppBoxStateChange, payload);
402
+ };
403
+
355
404
  public addAppsChangeListener = () => {
356
405
  this.refresher?.add("apps", () => {
357
406
  return safeListenPropsUpdated(
@@ -371,7 +420,6 @@ export class AppManager {
371
420
  });
372
421
  };
373
422
 
374
-
375
423
  private onMainViewIndexChange = (index: number) => {
376
424
  if (index !== undefined && this._prevSceneIndex !== index) {
377
425
  callbacks.emit("mainViewSceneIndexChange", index);
@@ -432,7 +480,7 @@ export class AppManager {
432
480
  if (!appAttributes) {
433
481
  throw new Error("appAttributes is undefined");
434
482
  }
435
- this.appCreateQueue.push(() => {
483
+ this.appCreateQueue.push<AppProxy>(() => {
436
484
  this.appStatus.set(id, AppStatus.StartCreate);
437
485
  return this.baseInsertApp(
438
486
  {
@@ -558,7 +606,7 @@ export class AppManager {
558
606
  private afterAddApp(appProxy: AppProxy | undefined) {
559
607
  if (appProxy && appProxy.box) {
560
608
  const box = appProxy.box;
561
- emitter.emit("move", {
609
+ boxEmitter.emit("move", {
562
610
  appId: appProxy.id,
563
611
  x: box?.intrinsicX,
564
612
  y: box?.intrinsicY,
@@ -694,7 +742,7 @@ export class AppManager {
694
742
  if (this.room) {
695
743
  if (this.store.getMainViewSceneIndex() === index) return;
696
744
  const sceneName = this.callbacksNode?.scenes[index];
697
- const scenePath =`${ROOT_DIR}${sceneName}`;
745
+ const scenePath = `${ROOT_DIR}${sceneName}`;
698
746
  if (sceneName) {
699
747
  const success = this.setMainViewFocusPath(scenePath);
700
748
  if (success) {
@@ -727,46 +775,6 @@ export class AppManager {
727
775
  }
728
776
  }
729
777
 
730
- private boxEventListener = (eventName: keyof EmitterEvent, payload: any) => {
731
- switch (eventName) {
732
- case "move": {
733
- this.dispatchInternalEvent(Events.AppMove, payload);
734
- this.store.updateAppState(payload.appId, AppAttributes.Position, {
735
- x: payload.x,
736
- y: payload.y,
737
- });
738
- break;
739
- }
740
- case "focus": {
741
- this.windowManger.safeSetAttributes({ focus: payload.appId });
742
- break;
743
- }
744
- case "resize": {
745
- if (payload.width && payload.height) {
746
- this.dispatchInternalEvent(Events.AppResize, payload);
747
- this.store.updateAppState(payload.appId, AppAttributes.Size, {
748
- width: payload.width,
749
- height: payload.height,
750
- });
751
- }
752
- break;
753
- }
754
- case "close": {
755
- const appProxy = this.appProxies.get(payload.appId);
756
- if (appProxy) {
757
- appProxy.destroy(false, true, payload.error);
758
- }
759
- break;
760
- }
761
- case "boxStateChange": {
762
- this.dispatchInternalEvent(Events.AppBoxStateChange, payload);
763
- break;
764
- }
765
- default:
766
- break;
767
- }
768
- };
769
-
770
778
  public focusByAttributes(apps: any) {
771
779
  if (apps && Object.keys(apps).length === this.boxManager?.boxSize) {
772
780
  const focusAppId = this.store.focus;
@@ -806,7 +814,7 @@ export class AppManager {
806
814
  this.displayer.callbacks.off(this.eventName, this.displayerStateListener);
807
815
  this.displayer.callbacks.off("onEnableWriteNowChanged", this.displayerWritableListener);
808
816
  this.appListeners.removeListeners();
809
- emitter.offAny(this.boxEventListener);
817
+ boxEmitter.clearListeners();
810
818
  emitter.clearListeners();
811
819
  if (this.appProxies.size) {
812
820
  this.appProxies.forEach(appProxy => {
@@ -0,0 +1,19 @@
1
+ import type { TELE_BOX_STATE } from "@netless/telebox-insider";
2
+ import Emittery from "emittery";
3
+
4
+ export type BoxMovePayload = { appId: string, x: number; y: number };
5
+ export type BoxFocusPayload = { appId: string };
6
+ export type BoxResizePayload = { appId: string, width: number; height: number, x?: number, y?: number };
7
+ export type BoxClosePayload = { appId: string, error?: Error };
8
+ export type BoxStateChangePayload = { appId: string, state: TELE_BOX_STATE };
9
+
10
+ export type BoxEvent = {
11
+ move: BoxMovePayload;
12
+ focus: BoxFocusPayload;
13
+ resize: BoxResizePayload;
14
+ close: BoxClosePayload;
15
+ boxStateChange: BoxStateChangePayload
16
+ }
17
+
18
+ export type BoxEmitterType = Emittery<BoxEvent>;
19
+ export const boxEmitter: BoxEmitterType = new Emittery();
package/src/BoxManager.ts CHANGED
@@ -2,6 +2,7 @@ import { AppAttributes, Events, MIN_HEIGHT, MIN_WIDTH } from "./constants";
2
2
  import { debounce } from "lodash";
3
3
  import { TELE_BOX_STATE, TeleBoxCollector, TeleBoxManager } from "@netless/telebox-insider";
4
4
  import { WindowManager } from "./index";
5
+ import type { BoxEmitterType } from "./BoxEmitter";
5
6
  import type { AddAppOptions, AppInitState } from "./index";
6
7
  import type {
7
8
  TeleBoxManagerUpdateConfig,
@@ -51,6 +52,7 @@ export type BoxManagerContext = {
51
52
  getMainView: () => View;
52
53
  updateAppState: (appId: string, field: AppAttributes, value: any) => void;
53
54
  emitter: EmitterType;
55
+ boxEmitter: BoxEmitterType;
54
56
  callbacks: CallbacksType;
55
57
  canOperate: () => boolean;
56
58
  notifyContainerRectUpdate: (rect: TeleBoxRect) => void;
@@ -62,6 +64,7 @@ export const createBoxManager = (
62
64
  manager: WindowManager,
63
65
  callbacks: CallbacksType,
64
66
  emitter: EmitterType,
67
+ boxEmitter: BoxEmitterType,
65
68
  options: CreateTeleBoxManagerConfig
66
69
  ) => {
67
70
  return new BoxManager(
@@ -76,6 +79,7 @@ export const createBoxManager = (
76
79
  setAppFocus: (appId: string) => manager.appManager?.store.setAppFocus(appId, true),
77
80
  callbacks,
78
81
  emitter,
82
+ boxEmitter
79
83
  },
80
84
  options
81
85
  );
@@ -88,7 +92,7 @@ export class BoxManager {
88
92
  private context: BoxManagerContext,
89
93
  private createTeleBoxManagerConfig?: CreateTeleBoxManagerConfig
90
94
  ) {
91
- const { emitter, callbacks } = context;
95
+ const { emitter, callbacks, boxEmitter } = context;
92
96
  this.teleBoxManager = this.setupBoxManager(createTeleBoxManagerConfig);
93
97
 
94
98
  // 使用 _xxx$.reaction 订阅修改的值, 不管有没有 skipUpdate, 修改值都会触发回调
@@ -123,19 +127,19 @@ export class BoxManager {
123
127
  });
124
128
  this.teleBoxManager.events.on("removed", boxes => {
125
129
  boxes.forEach(box => {
126
- emitter.emit("close", { appId: box.id });
130
+ boxEmitter.emit("close", { appId: box.id });
127
131
  });
128
132
  });
129
133
  this.teleBoxManager.events.on(
130
134
  "intrinsic_move",
131
135
  debounce((box: ReadonlyTeleBox): void => {
132
- emitter.emit("move", { appId: box.id, x: box.intrinsicX, y: box.intrinsicY });
136
+ boxEmitter.emit("move", { appId: box.id, x: box.intrinsicX, y: box.intrinsicY });
133
137
  }, 50)
134
138
  );
135
139
  this.teleBoxManager.events.on(
136
140
  "intrinsic_resize",
137
141
  debounce((box: ReadonlyTeleBox): void => {
138
- emitter.emit("resize", {
142
+ boxEmitter.emit("resize", {
139
143
  appId: box.id,
140
144
  width: box.intrinsicWidth,
141
145
  height: box.intrinsicHeight,
@@ -145,7 +149,7 @@ export class BoxManager {
145
149
  this.teleBoxManager.events.on("focused", box => {
146
150
  if (box) {
147
151
  if (this.canOperate) {
148
- emitter.emit("focus", { appId: box.id });
152
+ boxEmitter.emit("focus", { appId: box.id });
149
153
  } else {
150
154
  this.teleBoxManager.blurBox(box.id);
151
155
  }
@@ -221,7 +225,7 @@ export class BoxManager {
221
225
  const box = this.teleBoxManager.queryOne({ id: appId });
222
226
  if (box) {
223
227
  if (box.state === TELE_BOX_STATE.Maximized) {
224
- this.context.emitter.emit("resize", {
228
+ this.context.boxEmitter.emit("resize", {
225
229
  appId: appId,
226
230
  x: box.x,
227
231
  y: box.y,
@@ -1,5 +1,4 @@
1
1
  import App from "./Cursor.svelte";
2
- import { ApplianceMap } from "./icons";
3
2
  import { ApplianceNames } from "white-web-sdk";
4
3
  import { findMemberByUid } from "../Helper";
5
4
  import { omit } from "lodash";
@@ -159,8 +158,9 @@ export class Cursor {
159
158
 
160
159
  private getIcon() {
161
160
  if (this.member) {
162
- const applianceSrc = ApplianceMap[this.memberApplianceName || ApplianceNames.shape];
163
- return applianceSrc || ApplianceMap[ApplianceNames.shape];
161
+ const icons = this.cursorManager.applianceIcons;
162
+ const applianceSrc = icons[this.memberApplianceName || ApplianceNames.shape];
163
+ return applianceSrc || icons[ApplianceNames.shape];
164
164
  }
165
165
  }
166
166
 
@@ -5,10 +5,11 @@ import { emitter } from "../InternalEmitter";
5
5
  import { SideEffectManager } from "side-effect-manager";
6
6
  import { throttle } from "lodash";
7
7
  import { WindowManager } from "../index";
8
- import type { CursorMovePayload } from "../index";
8
+ import type { CursorMovePayload , ApplianceIcons} from "../index";
9
9
  import type { PositionType } from "../AttributesDelegate";
10
10
  import type { Point, RoomMember, View } from "white-web-sdk";
11
11
  import type { AppManager } from "../AppManager";
12
+ import { ApplianceMap } from "./icons";
12
13
 
13
14
  export type EventType = {
14
15
  type: PositionType;
@@ -20,6 +21,7 @@ export type MoveCursorParams = {
20
21
  x: number;
21
22
  y: number;
22
23
  };
24
+
23
25
  export class CursorManager {
24
26
  public containerRect?: DOMRect;
25
27
  public wrapperRect?: DOMRect;
@@ -28,8 +30,9 @@ export class CursorManager {
28
30
  private mainViewElement?: HTMLDivElement;
29
31
  private sideEffectManager = new SideEffectManager();
30
32
  private store = this.manager.store;
33
+ public applianceIcons: ApplianceIcons = ApplianceMap;
31
34
 
32
- constructor(private manager: AppManager, private enableCursor: boolean) {
35
+ constructor(private manager: AppManager, private enableCursor: boolean, applianceIcons?: ApplianceIcons) {
33
36
  this.roomMembers = this.manager.room?.state.roomMembers;
34
37
  const wrapper = WindowManager.wrapper;
35
38
  if (wrapper) {
@@ -42,6 +45,9 @@ export class CursorManager {
42
45
  this.sideEffectManager.add(() => {
43
46
  return emitter.on("playgroundSizeChange", () => this.updateContainerRect());
44
47
  });
48
+ if (applianceIcons) {
49
+ this.applianceIcons = { ...ApplianceMap, ...applianceIcons };
50
+ }
45
51
  }
46
52
 
47
53
  private onCursorMove = (payload: CursorMovePayload) => {
package/src/Helper.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { getVersionNumber } from "./Utils/Common";
1
+ import { getVersionNumber, wait } from "./Utils/Common";
2
+ import { log } from "./Utils/log";
2
3
  import { REQUIRE_VERSION } from "./constants";
3
4
  import { WhiteVersion } from "white-web-sdk";
4
5
  import { WhiteWebSDKInvalidError } from "./Utils/error";
@@ -45,3 +46,18 @@ export const findMemberByUid = (room: Room | undefined, uid: string) => {
45
46
  const roomMembers = room?.state.roomMembers;
46
47
  return roomMembers?.find(member => member.payload?.uid === uid);
47
48
  };
49
+
50
+ export const createInvisiblePlugin = async (room: Room) => {
51
+ try {
52
+ const manager = (await room.createInvisiblePlugin(WindowManager, {})) as WindowManager;
53
+ return manager;
54
+ } catch (error) {
55
+ // 如果有两个用户同时调用 WindowManager.mount 有概率出现这个错误
56
+ if (error.message === `invisible plugin "WindowManager" exits`) {
57
+ await wait(200);
58
+ return room.getInvisiblePlugin(WindowManager.kind) as WindowManager;
59
+ } else {
60
+ log("createInvisiblePlugin failed", error);
61
+ }
62
+ }
63
+ };
@@ -8,10 +8,6 @@ export type RemoveSceneParams = {
8
8
  export type EmitterEvent = {
9
9
  onCreated: undefined;
10
10
  InitReplay: AppInitState;
11
- move: { appId: string; x: number; y: number };
12
- focus: { appId: string };
13
- close: { appId: string };
14
- resize: { appId: string; width: number; height: number; x?: number; y?: number };
15
11
  error: Error;
16
12
  seekStart: undefined;
17
13
  seek: number;
@@ -4,6 +4,7 @@ import { RoomPhase } from "white-web-sdk";
4
4
  import type { Room } from "white-web-sdk";
5
5
  import type { EmitterType } from "./InternalEmitter";
6
6
  import { EnsureReconnectEvent } from "./constants";
7
+ import { wait } from "./Utils/Common";
7
8
 
8
9
  export type ReconnectRefresherContext = {
9
10
  emitter: EmitterType;
@@ -41,19 +42,24 @@ export class ReconnectRefresher {
41
42
  this.ctx = ctx;
42
43
  }
43
44
 
44
- private onPhaseChanged = (phase: RoomPhase) => {
45
+ private onPhaseChanged = async (phase: RoomPhase) => {
45
46
  if (phase === RoomPhase.Reconnecting) {
46
47
  this.ctx.emitter.emit("startReconnect");
47
48
  }
48
49
  if (phase === RoomPhase.Connected && this.phase === RoomPhase.Reconnecting) {
49
- this.room?.dispatchMagixEvent(EnsureReconnectEvent, {});
50
+ if (this.room?.isWritable) {
51
+ this.room?.dispatchMagixEvent(EnsureReconnectEvent, {});
52
+ } else {
53
+ await wait(500);
54
+ this.onReconnected();
55
+ }
50
56
  }
51
57
  this.phase = phase;
52
58
  };
53
59
 
54
60
  private onReconnected = debounce(() => {
55
61
  this._onReconnected();
56
- }, 3000);
62
+ }, 1000);
57
63
 
58
64
  private _onReconnected = () => {
59
65
  log("onReconnected refresh reactors");
@@ -1,8 +1,7 @@
1
1
  import { callbacks } from "../callback";
2
2
  import { SETUP_APP_DELAY } from "../constants";
3
- import type { AppProxy } from "../App";
4
3
 
5
- export type Invoker = () => Promise<AppProxy | undefined>;
4
+ export type Invoker<T = any> = () => Promise<T | undefined>;
6
5
 
7
6
  export class AppCreateQueue {
8
7
  private list: Invoker[] = [];
@@ -16,7 +15,7 @@ export class AppCreateQueue {
16
15
  }, 50);
17
16
  }
18
17
 
19
- public push(item: Invoker) {
18
+ public push<T>(item: Invoker<T>) {
20
19
  this.list.push(item);
21
20
  this.invoke();
22
21
  if (this.timer === undefined && this.list.length > 0) {