@netless/window-manager 0.2.15 → 0.2.19-canary.0

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.
@@ -1,17 +1,17 @@
1
- import { Cursor } from './Cursor';
2
- import { CursorState } from '../constants';
3
- import { debounce } from 'lodash';
4
- import { Fields } from '../AttributesDelegate';
5
- import { onObjectInserted } from '../Utils/Reactive';
6
- import { WindowManager } from '../index';
7
- import type { PositionType } from '../AttributesDelegate';
8
- import type { RoomMember } from "white-web-sdk";
1
+ import { Cursor } from "./Cursor";
2
+ import { CursorState } from "../constants";
3
+ import { debounce } from "lodash";
4
+ import { Fields } from "../AttributesDelegate";
5
+ import { onObjectInserted } from "../Utils/Reactive";
6
+ import { WindowManager } from "../index";
7
+ import type { PositionType } from "../AttributesDelegate";
8
+ import type { Point, RoomMember, View } from "white-web-sdk";
9
9
  import type { AppManager } from "../AppManager";
10
10
 
11
11
  export type EventType = {
12
- type: PositionType,
13
- id?: string
14
- }
12
+ type: PositionType;
13
+ id?: string;
14
+ };
15
15
  export class CursorManager {
16
16
  public containerRect?: DOMRect;
17
17
  public wrapperRect?: DOMRect;
@@ -19,7 +19,7 @@ export class CursorManager {
19
19
  public cursorInstances: Map<string, Cursor> = new Map();
20
20
  public roomMembers?: readonly RoomMember[];
21
21
  private mainViewElement?: HTMLDivElement;
22
- private delegate = this.appManager.delegate;
22
+ private store = this.appManager.store;
23
23
 
24
24
  constructor(private manager: WindowManager, private appManager: AppManager) {
25
25
  this.roomMembers = this.manager.room?.state.roomMembers;
@@ -76,34 +76,11 @@ export class CursorManager {
76
76
  }
77
77
 
78
78
  public get boxState() {
79
- return this.delegate.getBoxState();
80
- }
81
-
82
- public get focusBox() {
83
- return this.appManager.boxManager.getFocusBox();
79
+ return this.store.getBoxState();
84
80
  }
85
81
 
86
82
  public get focusView() {
87
- return this.appManager.focusApp?.view
88
- }
89
-
90
- /**
91
- * 因为窗口内框在不同分辨率下的大小不一样,所以这里通过来鼠标事件的 target 来判断是在主白板还是在 APP 中
92
- */
93
- private getType = (event: MouseEvent | Touch): EventType => {
94
- const target = event.target as HTMLElement;
95
- const targetIsMain = target.parentElement === this.mainViewElement;
96
- if (targetIsMain) {
97
- return { type: "main" };
98
- } else {
99
- if (!this.focusView) return { type: "main" };
100
- const focusApp = this.appManager.focusApp;
101
- const targetIsFocusApp = target.parentElement === focusApp?.view?.divElement;
102
- if (targetIsFocusApp) {
103
- return { type: "app" };
104
- }
105
- return { type: "main" };
106
- }
83
+ return this.appManager.focusApp?.view;
107
84
  }
108
85
 
109
86
  private mouseMoveListener = debounce((event: MouseEvent) => {
@@ -117,58 +94,70 @@ export class CursorManager {
117
94
  }
118
95
  }, 5);
119
96
 
120
- private initCursorAttributes() {
121
- this.delegate.updateCursor(this.observerId, {
122
- x: 0,
123
- y: 0,
124
- type: "main"
125
- });
126
- this.delegate.updateCursorState(this.observerId, CursorState.Leave);
97
+ private updateCursor(event: EventType, clientX: number, clientY: number) {
98
+ if (this.wrapperRect && this.manager.canOperate) {
99
+ const view = event.type === "main" ? this.appManager.mainView : this.focusView;
100
+ const point = this.getPoint(view, clientX, clientY);
101
+ if (point) {
102
+ this.setNormalCursorState();
103
+ this.store.updateCursor(this.observerId, {
104
+ x: point.x,
105
+ y: point.y,
106
+ ...event,
107
+ });
108
+ }
109
+ }
127
110
  }
128
111
 
129
- public getFocusBox() {
130
- return this.appManager.boxManager.getFocusBox();
112
+ private getPoint = (view: View | undefined, clientX: number, clientY: number): Point | undefined => {
113
+ const rect = view?.divElement?.getBoundingClientRect();
114
+ if (rect) {
115
+ const point = view?.convertToPointInWorld({
116
+ x: clientX - rect.x,
117
+ y: clientY - rect.y,
118
+ });
119
+ return point;
120
+ }
131
121
  }
132
122
 
133
- private updateCursor(event: EventType, clientX: number, clientY: number) {
134
- if (this.wrapperRect && this.manager.canOperate) {
135
- if (event.type === "main") {
136
- const mainView = this.appManager.mainView;
137
- const rect = mainView?.divElement?.getBoundingClientRect();
138
- if (rect) {
139
- const point = mainView.convertToPointInWorld({
140
- x: clientX - rect.x,
141
- y: clientY - rect.y,
142
- })
143
- this.setNormalCursorState();
144
- this.delegate.updateCursor(this.observerId, {
145
- x: point.x, y: point.y, ...event
146
- });
147
- }
148
- } else if (event.type === "app") {
149
- const viewRect = this.focusView?.divElement?.getBoundingClientRect();
150
- if (viewRect) {
151
- const worldPosition = this.focusView?.convertToPointInWorld({ x: clientX - viewRect.x, y: clientY - viewRect.y });
152
- if (!worldPosition) return;
153
- this.setNormalCursorState();
154
- this.delegate.updateCursor(this.observerId, {
155
- x: worldPosition.x, y: worldPosition.y, ...event
156
- });
157
- }
123
+ /**
124
+ * 因为窗口内框在不同分辨率下的大小不一样,所以这里通过来鼠标事件的 target 来判断是在主白板还是在 APP
125
+ */
126
+ private getType = (event: MouseEvent | Touch): EventType => {
127
+ const target = event.target as HTMLElement;
128
+ const focusApp = this.appManager.focusApp;
129
+ switch (target.parentElement) {
130
+ case this.mainViewElement: {
131
+ return { type: "main" };
132
+ }
133
+ case focusApp?.view?.divElement: {
134
+ return { type: "app" };
135
+ }
136
+ default: {
137
+ return { type: "main" };
158
138
  }
159
139
  }
140
+ };
141
+
142
+ private initCursorAttributes() {
143
+ this.store.updateCursor(this.observerId, {
144
+ x: 0,
145
+ y: 0,
146
+ type: "main",
147
+ });
148
+ this.store.updateCursorState(this.observerId, CursorState.Leave);
160
149
  }
161
-
150
+
162
151
  private setNormalCursorState() {
163
- const cursorState = this.delegate.getCursorState(this.observerId)
152
+ const cursorState = this.store.getCursorState(this.observerId);
164
153
  if (cursorState !== CursorState.Normal) {
165
- this.delegate.updateCursorState(this.observerId, CursorState.Normal);
154
+ this.store.updateCursorState(this.observerId, CursorState.Normal);
166
155
  }
167
156
  }
168
157
 
169
158
  private mouseLeaveListener = () => {
170
159
  this.hideCursor(this.observerId);
171
- this.delegate.updateCursorState(this.observerId, CursorState.Leave);
160
+ this.store.updateCursorState(this.observerId, CursorState.Leave);
172
161
  };
173
162
 
174
163
  public updateContainerRect() {
@@ -187,7 +176,7 @@ export class CursorManager {
187
176
  }
188
177
 
189
178
  public cleanMemberCursor(memberId: string) {
190
- this.delegate.cleanCursor(memberId);
179
+ this.store.cleanCursor(memberId);
191
180
  const cursor = this.cursorInstances.get(memberId);
192
181
  if (cursor) {
193
182
  cursor.destroy();
@@ -215,7 +204,7 @@ export class CursorManager {
215
204
  if (instance) {
216
205
  instance.destroy();
217
206
  }
218
- this.delegate.cleanCursor(memberId);
207
+ this.store.cleanCursor(memberId);
219
208
  });
220
209
  }
221
210
 
package/src/MainView.ts CHANGED
@@ -1,26 +1,44 @@
1
- import { AnimationMode, reaction } from 'white-web-sdk';
1
+ import { AnimationMode, reaction, ViewVisionMode } from 'white-web-sdk';
2
2
  import { Fields } from './AttributesDelegate';
3
3
  import { debounce, isEmpty, isEqual } from 'lodash';
4
4
  import type { Camera, Size, View } from "white-web-sdk";
5
5
  import type { AppManager } from "./AppManager";
6
- import { emitter } from './index';
6
+ import { callbacks, emitter } from './index';
7
+ import { notifyMainViewModeChange, setViewFocusScenePath, setViewMode } from './Utils/Common';
7
8
 
8
9
  export class MainViewProxy {
9
10
  private scale?: number;
10
- private delegate = this.manager.delegate;
11
+ private store = this.manager.store;
11
12
  private started = false;
12
- private observerId = this.manager.displayer.observerId;
13
+ private mainViewIsAddListener = false;
14
+ private mainView: View;
13
15
 
14
16
  constructor(
15
17
  private manager: AppManager,
16
18
  ) {
19
+ this.mainView = this.createMainView();
17
20
  emitter.once("mainViewMounted").then(() => {
21
+ this.view.callbacks.on("onCameraUpdated", this.mainViewCameraListener);
18
22
  setTimeout(() => {
19
23
  this.start();
20
24
  }, 300); // 等待 mainView 挂载完毕再进行监听,否则会触发不必要的 onSizeUpdated
21
25
  })
22
26
  }
23
27
 
28
+ public start() {
29
+ if (this.started) return;
30
+ this.addCameraListener();
31
+ this.manager.refresher?.add(Fields.MainViewCamera, this.cameraReaction);
32
+ this.manager.refresher?.add(Fields.MainViewSize, this.sizeReaction);
33
+ this.view.callbacks.on("onSizeUpdated", this.sizeListener);
34
+ this.started = true;
35
+ }
36
+
37
+
38
+ private get observerId() {
39
+ return this.manager.displayer.observerId;
40
+ }
41
+
24
42
  private cameraReaction = () => {
25
43
  return reaction(
26
44
  () => this.manager.attributes?.[Fields.MainViewCamera],
@@ -41,7 +59,7 @@ export class MainViewProxy {
41
59
  size => {
42
60
  if (size && size.id !== this.observerId) {
43
61
  this.moveCameraToContian(size);
44
- this.moveCamera(this.delegate.getMainViewCamera());
62
+ this.moveCamera(this.store.getMainViewCamera());
45
63
  }
46
64
  },
47
65
  {
@@ -51,22 +69,65 @@ export class MainViewProxy {
51
69
  }
52
70
 
53
71
  public get view(): View {
54
- return this.manager.viewManager.mainView;
72
+ return this.mainView;
73
+ }
74
+
75
+ public createMainView(): View {
76
+ const mainView = this.manager.displayer.views.createView();
77
+ this.manager.cameraStore.setCamera("mainView", mainView.camera);
78
+ mainView.callbacks.on("onSizeUpdated", () => {
79
+ this.manager.boxManager.updateManagerRect();
80
+ });
81
+ const mainViewScenePath = this.store.getMainViewScenePath();
82
+ if (mainViewScenePath) {
83
+ setViewFocusScenePath(mainView, mainViewScenePath);
84
+ }
85
+ if (!this.store.focus) {
86
+ this.switchViewModeToWriter();
87
+ }
88
+ return mainView;
55
89
  }
56
90
 
57
91
  private cameraListener = (camera: Camera) => {
58
- this.delegate.setMainViewCamera({ ...camera, id: this.observerId});
59
- if (this.delegate.getMainViewSize()?.id !== this.observerId) {
92
+ this.store.setMainViewCamera({ ...camera, id: this.observerId});
93
+ if (this.store.getMainViewSize()?.id !== this.observerId) {
60
94
  this.setMainViewSize(this.view.size);
61
95
  }
62
96
  }
63
97
 
98
+ public addMainViewListener(): void {
99
+ if (this.mainViewIsAddListener) return;
100
+ if (this.view.divElement) {
101
+ this.view.divElement.addEventListener("click", this.mainViewClickListener);
102
+ this.view.divElement.addEventListener("touchend", this.mainViewClickListener);
103
+ this.mainViewIsAddListener = true;
104
+ }
105
+ }
106
+
107
+ public removeMainViewListener(): void {
108
+ if (this.view.divElement) {
109
+ this.view.divElement.removeEventListener("click", this.mainViewClickListener);
110
+ this.view.divElement.removeEventListener("touchend", this.mainViewClickListener);
111
+ }
112
+ }
113
+
114
+ private mainViewClickListener = () => {
115
+ this.mainViewClickHandler();
116
+ };
117
+
118
+ public async mainViewClickHandler(): Promise<void> {
119
+ if (!this.manager.canOperate) return;
120
+ if (this.view.mode === ViewVisionMode.Writable) return;
121
+ this.store.cleanFocus();
122
+ this.manager.boxManager.blurFocusBox();
123
+ }
124
+
64
125
  private sizeListener = (size: Size) => {
65
126
  this.setMainViewSize(size);
66
127
  }
67
128
 
68
129
  public setMainViewSize = debounce(size => {
69
- this.manager.delegate.setMainViewSize({ ...size, id: this.observerId });
130
+ this.store.setMainViewSize({ ...size, id: this.observerId });
70
131
  }, 50);
71
132
 
72
133
  private addCameraListener() {
@@ -77,6 +138,22 @@ export class MainViewProxy {
77
138
  this.view.callbacks.off("onCameraUpdatedByDevice", this.cameraListener);
78
139
  }
79
140
 
141
+ private mainViewCameraListener = (camera: Camera) => {
142
+ this.manager.cameraStore.setCamera("mainView", camera);
143
+ };
144
+
145
+ public switchViewModeToWriter(): void {
146
+ if (!this.manager.canOperate) return;
147
+ if (this.view) {
148
+ if (this.view.mode === ViewVisionMode.Writable) return;
149
+ this.view.callbacks.off("onCameraUpdated", this.mainViewCameraListener);
150
+ notifyMainViewModeChange(callbacks, ViewVisionMode.Writable);
151
+ setViewMode(this.view, ViewVisionMode.Writable);
152
+ this.manager.cameraStore.recoverCamera("mainView", this.view);
153
+ this.view.callbacks.on("onCameraUpdated", this.mainViewCameraListener);
154
+ }
155
+ }
156
+
80
157
  public moveCameraToContian(size: Size): void {
81
158
  if (!isEmpty(size)) {
82
159
  this.view.moveCameraToContain({
@@ -104,15 +181,6 @@ export class MainViewProxy {
104
181
  }
105
182
  }
106
183
 
107
- public start() {
108
- if (this.started) return;
109
- this.addCameraListener();
110
- this.manager.refresher?.add(Fields.MainViewCamera, this.cameraReaction);
111
- this.manager.refresher?.add(Fields.MainViewSize, this.sizeReaction);
112
- this.view.callbacks.on("onSizeUpdated", this.sizeListener);
113
- this.started = true;
114
- }
115
-
116
184
  public stop() {
117
185
  this.removeCameraListener();
118
186
  this.manager.refresher?.remove(Fields.MainViewCamera);
@@ -28,7 +28,7 @@ export const replaceRoomFunction = (room: Room, manager: AppManager) => {
28
28
  manager.mainView.disableCameraTransform = disable;
29
29
  },
30
30
  });
31
-
31
+
32
32
  room.moveCamera = (camera: Camera) => manager.mainView.moveCamera(camera);
33
33
  room.moveCameraToContain = (...args) => manager.mainView.moveCameraToContain(...args);
34
34
  room.convertToPointInWorld = (...args) => manager.mainView.convertToPointInWorld(...args);
package/src/constants.ts CHANGED
@@ -43,7 +43,7 @@ export const REQUIRE_VERSION = "2.13.16";
43
43
  export const MIN_WIDTH = 340 / 720;
44
44
  export const MIN_HEIGHT = 340 / 720;
45
45
 
46
- export const SET_SCENEPATH_DELAY = 50; // 设置 scenePath 的延迟事件
46
+ export const SET_SCENEPATH_DELAY = 100; // 设置 scenePath 的延迟事件
47
47
 
48
48
  export const DEFAULT_COLLECTOR_STYLE = { right: "10px", bottom: "15px", position: "absolute" };
49
49
 
package/src/index.ts CHANGED
@@ -35,7 +35,6 @@ import {
35
35
  isRoom,
36
36
  RoomPhase,
37
37
  ViewMode,
38
- ViewVisionMode,
39
38
  WhiteVersion,
40
39
  } from "white-web-sdk";
41
40
  import type {
@@ -49,7 +48,8 @@ import type {
49
48
  AnimationMode,
50
49
  CameraBound,
51
50
  Point,
52
- Rectangle} from "white-web-sdk";
51
+ Rectangle,
52
+ ViewVisionMode} from "white-web-sdk";
53
53
  import type { AppListeners } from "./AppListener";
54
54
  import type { NetlessApp, RegisterParams } from "./typings";
55
55
  import type { TELE_BOX_STATE } from "./BoxManager";
@@ -168,6 +168,8 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
168
168
  public static containerSizeRatio = DEFAULT_CONTAINER_RATIO;
169
169
  private static isCreated = false;
170
170
 
171
+ public version = "0.2.19-canary.0";
172
+
171
173
  public appListeners?: AppListeners;
172
174
 
173
175
  public readonly?: boolean;
@@ -381,7 +383,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
381
383
  throw new InvalidScenePath();
382
384
  }
383
385
  for (const appId in this.apps) {
384
- const appScenePath = appManager.delegate.getAppScenePath(appId);
386
+ const appScenePath = appManager.store.getAppScenePath(appId);
385
387
  if (appScenePath && appScenePath === scenePath) {
386
388
  console.warn(`[WindowManager]: ScenePath ${scenePath} Already opened`);
387
389
  return;
@@ -410,18 +412,18 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
410
412
  /**
411
413
  * 设置 mainView 的 ScenePath, 并且切换白板为可写状态
412
414
  */
413
- public setMainViewScenePath(scenePath: string): void {
415
+ public async setMainViewScenePath(scenePath: string): Promise<void> {
414
416
  if (this.appManager) {
415
- this.appManager.setMainViewScenePath(scenePath);
417
+ await this.appManager.setMainViewScenePath(scenePath);
416
418
  }
417
419
  }
418
420
 
419
421
  /**
420
422
  * 设置 mainView 的 SceneIndex, 并且切换白板为可写状态
421
423
  */
422
- public setMainViewSceneIndex(index: number): void {
424
+ public async setMainViewSceneIndex(index: number): Promise<void> {
423
425
  if (this.appManager) {
424
- this.appManager.setMainViewSceneIndex(index);
426
+ await this.appManager.setMainViewSceneIndex(index);
425
427
  }
426
428
  }
427
429
 
@@ -429,14 +431,14 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
429
431
  * 返回 mainView 的 ScenePath
430
432
  */
431
433
  public getMainViewScenePath(): string {
432
- return this.appManager?.delegate.getMainViewScenePath();
434
+ return this.appManager?.store.getMainViewScenePath();
433
435
  }
434
436
 
435
437
  /**
436
438
  * 返回 mainView 的 SceneIndex
437
439
  */
438
440
  public getMainViewSceneIndex(): number {
439
- return this.appManager?.delegate.getMainViewSceneIndex();
441
+ return this.appManager?.store.getMainViewSceneIndex();
440
442
  }
441
443
 
442
444
  /**
@@ -453,7 +455,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
453
455
  * 切换 mainView 为可写
454
456
  */
455
457
  public switchMainViewToWriter(): Promise<void> | undefined {
456
- return this.appManager?.viewManager.mainViewClickHandler();
458
+ return this.appManager?.mainViewProxy.mainViewClickHandler();
457
459
  }
458
460
 
459
461
  /**
@@ -469,8 +471,8 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
469
471
  public setViewMode(mode: ViewMode): void {
470
472
  if (!this.canOperate) return;
471
473
  if (mode === ViewMode.Broadcaster) {
472
- this.appManager?.delegate.setMainViewCamera({ ...this.mainView.camera, id: this.displayer.observerId });
473
- this.appManager?.delegate.setMainViewSize({ ...this.mainView.size, id: this.displayer.observerId });
474
+ this.appManager?.store.setMainViewCamera({ ...this.mainView.camera, id: this.displayer.observerId });
475
+ this.appManager?.store.setMainViewSize({ ...this.mainView.size, id: this.displayer.observerId });
474
476
  this.appManager?.mainViewProxy.start();
475
477
  }
476
478
  if (mode === ViewMode.Freedom) {
@@ -481,7 +483,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
481
483
 
482
484
  public get mainView(): View {
483
485
  if (this.appManager) {
484
- return this.appManager.viewManager.mainView;
486
+ return this.appManager.mainViewProxy.view;
485
487
  } else {
486
488
  throw new AppManagerNotInitError();
487
489
  }
@@ -489,14 +491,14 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
489
491
 
490
492
  public get camera(): Camera {
491
493
  if (this.appManager) {
492
- return this.appManager.viewManager.mainView.camera;
494
+ return this.appManager.mainViewProxy.view.camera;
493
495
  } else {
494
496
  throw new AppManagerNotInitError();
495
497
  }
496
498
  }
497
499
 
498
500
  public get apps(): Apps | undefined {
499
- return this.appManager?.delegate.apps();
501
+ return this.appManager?.store.apps();
500
502
  }
501
503
 
502
504
  public get boxState(): TeleBoxState {
@@ -569,21 +571,8 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
569
571
 
570
572
  private bindMainView(divElement: HTMLDivElement, disableCameraTransform: boolean) {
571
573
  if (this.appManager) {
572
- const mainView = this.appManager.viewManager.mainView;
573
- mainView.disableCameraTransform = disableCameraTransform;
574
- mainView.divElement = divElement;
574
+ this.appManager.bindMainView(divElement, disableCameraTransform);
575
575
  this.cursorManager?.setMainViewDivElement(divElement);
576
- if (!mainView.focusScenePath) {
577
- this.appManager.delegate.setMainViewFocusPath();
578
- }
579
- if (
580
- this.appManager.delegate.focus === undefined &&
581
- mainView.mode !== ViewVisionMode.Writable
582
- ) {
583
- this.appManager.viewManager.switchMainViewToWriter();
584
- }
585
- this.appManager.viewManager.addMainViewListener();
586
- emitter.emit("mainViewMounted");
587
576
  }
588
577
  }
589
578
 
@@ -614,12 +603,6 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
614
603
  }
615
604
  }
616
605
 
617
- private safeDispatchMagixEvent(event: string, payload: any) {
618
- if (this.canOperate) {
619
- (this.displayer as Room).dispatchMagixEvent(event, payload);
620
- }
621
- }
622
-
623
606
  private isDynamicPPT(scenes: SceneDefinition[]) {
624
607
  const sceneSrc = scenes[0]?.ppt?.src;
625
608
  return sceneSrc?.startsWith("pptx://");
package/src/sdk.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { isBoolean } from 'lodash';
1
2
  import { WhiteWebSdk } from 'white-web-sdk';
2
3
  import { WindowManager } from './index';
3
4
  import type { MountParams } from "./index";
@@ -30,6 +31,9 @@ export class WhiteWindowSDK {
30
31
  room,
31
32
  ...params.mountParams
32
33
  });
34
+ if (isBoolean(params.joinRoomParams.disableCameraTransform)) {
35
+ manager.mainView.disableCameraTransform = params.joinRoomParams.disableCameraTransform;
36
+ }
33
37
  return manager;
34
38
  }
35
39
  }