@netless/window-manager 0.2.18 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/window-manager",
3
- "version": "0.2.18",
3
+ "version": "0.2.19-canary.0",
4
4
  "description": "",
5
5
  "main": "dist/index.es.js",
6
6
  "module": "dist/index.es.js",
@@ -2,10 +2,8 @@ import { Events, MagixEventName } from './constants';
2
2
  import { ViewVisionMode } from 'white-web-sdk';
3
3
  import type { Event } from "white-web-sdk";
4
4
  import type { TeleBox } from "@netless/telebox-insider";
5
- import type { ViewManager } from "./ViewManager";
6
5
  import type { AppProxy } from "./AppProxy";
7
6
  import type { AppManager } from "./AppManager";
8
- import type { WindowManager } from "./index";
9
7
 
10
8
  export class AppListeners {
11
9
  private displayer = this.manager.displayer;
@@ -13,8 +11,6 @@ export class AppListeners {
13
11
 
14
12
  constructor(
15
13
  private manager: AppManager,
16
- private windowManager: WindowManager,
17
- private viewManager: ViewManager,
18
14
  private appProxies: Map<string, AppProxy>
19
15
  ) {}
20
16
 
package/src/AppManager.ts CHANGED
@@ -14,7 +14,8 @@ import { genAppId, makeValidScenePath, setScenePath } from './Utils/Common';
14
14
  import {
15
15
  isPlayer,
16
16
  isRoom,
17
- ScenePathType
17
+ ScenePathType,
18
+ ViewVisionMode
18
19
  } from 'white-web-sdk';
19
20
  import { log } from './Utils/log';
20
21
  import { MainViewProxy } from './MainView';
@@ -41,21 +42,15 @@ export class AppManager {
41
42
  constructor(public windowManger: WindowManager, options: CreateCollectorConfig) {
42
43
  this.displayer = windowManger.displayer;
43
44
  this.cameraStore = new CameraStore();
45
+ this.mainViewProxy = new MainViewProxy(this);
44
46
  this.viewManager = new ViewManager(this.displayer as Room, this, this.cameraStore);
45
- this.boxManager = new BoxManager(this, this.viewManager.mainView, this.appProxies, options);
46
- this.appListeners = new AppListeners(
47
- this,
48
- this.windowManger,
49
- this.viewManager,
50
- this.appProxies
51
- );
47
+ this.boxManager = new BoxManager(this, this.mainViewProxy.view, this.appProxies, options);
48
+ this.appListeners = new AppListeners(this, this.appProxies);
52
49
  this.displayer.callbacks.on(this.eventName, this.displayerStateListener);
53
50
  this.appListeners.addListeners();
54
51
 
55
52
  this.refresher = new ReconnectRefresher(this.room, this);
56
53
 
57
- this.mainViewProxy = new MainViewProxy(this);
58
-
59
54
  emitter.once("onCreated").then(() => this.onCreated());
60
55
 
61
56
  if (isPlayer(this.displayer)) {
@@ -128,6 +123,23 @@ export class AppManager {
128
123
  });
129
124
  }
130
125
 
126
+ public bindMainView(divElement: HTMLDivElement, disableCameraTransform: boolean) {
127
+ const mainView = this.mainViewProxy.view;
128
+ mainView.disableCameraTransform = disableCameraTransform;
129
+ mainView.divElement = divElement;
130
+ if (!mainView.focusScenePath) {
131
+ this.store.setMainViewFocusPath();
132
+ }
133
+ if (
134
+ this.store.focus === undefined &&
135
+ mainView.mode !== ViewVisionMode.Writable
136
+ ) {
137
+ this.viewManager.switchMainViewToWriter();
138
+ }
139
+ this.mainViewProxy.addMainViewListener();
140
+ emitter.emit("mainViewMounted");
141
+ }
142
+
131
143
  public async addApp(params: AddAppParams, isDynamicPPT: boolean): Promise<string | undefined> {
132
144
  log("addApp", params);
133
145
  const { appId, needFocus } = await this.beforeAddApp(params, isDynamicPPT);
@@ -225,7 +237,7 @@ export class AppManager {
225
237
  });
226
238
  if (isWritable === true) {
227
239
  if (!this.store.focus) {
228
- this.viewManager.switchMainViewModeToWriter();
240
+ this.mainViewProxy.switchViewModeToWriter();
229
241
  }
230
242
  this.mainView.disableCameraTransform = false;
231
243
  } else {
package/src/AppProxy.ts CHANGED
@@ -65,7 +65,6 @@ export class AppProxy extends Base {
65
65
  if (this.params.options?.scenePath) {
66
66
  // 只有传入了 scenePath 的 App 才会创建 View
67
67
  this.createView();
68
- this.addCameraListener();
69
68
  }
70
69
  this.isAddApp = isAddApp;
71
70
  }
@@ -192,16 +191,20 @@ export class AppProxy extends Base {
192
191
 
193
192
  public switchToWritable() {
194
193
  if (this.view) {
194
+ if (this.view.mode === ViewVisionMode.Writable) return;
195
+ this.removeCameraListener();
195
196
  try {
196
- if (this.view.mode === ViewVisionMode.Writable) return;
197
197
  if (this.manager.mainView.mode === ViewVisionMode.Writable) {
198
198
  this.store.setMainViewFocusPath();
199
199
  notifyMainViewModeChange(callbacks, ViewVisionMode.Freedom);
200
200
  setViewMode(this.manager.mainView, ViewVisionMode.Freedom);
201
201
  }
202
202
  setViewMode(this.view, ViewVisionMode.Writable);
203
+ this.recoverCamera();
203
204
  } catch (error) {
204
205
  log("switch view failed", error);
206
+ } finally {
207
+ this.addCameraListener();
205
208
  }
206
209
  }
207
210
  }
@@ -335,8 +338,9 @@ export class AppProxy extends Base {
335
338
  this.view?.callbacks.off("onCameraUpdated", this.cameraListener);
336
339
  }
337
340
 
338
- private createView(): View {
339
- const view = this.viewManager.createView(this.id);
341
+ private async createView(): Promise<View> {
342
+ const view = await this.viewManager.createView(this.id);
343
+ this.addCameraListener();
340
344
  this.setViewFocusScenePath();
341
345
  return view;
342
346
  }
@@ -94,16 +94,6 @@ export class AttributesDelegate {
94
94
  this.manager.safeSetAttributes({ [Fields.Focus]: undefined });
95
95
  }
96
96
 
97
- public cleanAttributes() {
98
- this.manager.safeSetAttributes({
99
- [Fields.Apps]: undefined,
100
- [Fields.BoxState]: undefined,
101
- [Fields.Focus]: undefined,
102
- _mainScenePath: undefined,
103
- _mainSceneIndex: undefined,
104
- });
105
- }
106
-
107
97
  public getAppSceneIndex(id: string) {
108
98
  return this.getAppState(id)?.[AppAttributes.SceneIndex];
109
99
  }
@@ -134,10 +134,6 @@ export class Cursor {
134
134
  return get(this.cursors, [this.memberId, Fields.Position]);
135
135
  }
136
136
 
137
- public getFocusBox() {
138
- return this.cursorManager.getFocusBox();
139
- }
140
-
141
137
  private autoHidden() {
142
138
  if (this.timer) {
143
139
  clearTimeout(this.timer);
@@ -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;
@@ -79,31 +79,8 @@ export class CursorManager {
79
79
  return this.store.getBoxState();
80
80
  }
81
81
 
82
- public get focusBox() {
83
- return this.appManager.boxManager.getFocusBox();
84
- }
85
-
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,50 +94,62 @@ export class CursorManager {
117
94
  }
118
95
  }, 5);
119
96
 
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
+ }
110
+ }
111
+
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
+ }
121
+ }
122
+
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" };
138
+ }
139
+ }
140
+ };
141
+
120
142
  private initCursorAttributes() {
121
143
  this.store.updateCursor(this.observerId, {
122
144
  x: 0,
123
145
  y: 0,
124
- type: "main"
146
+ type: "main",
125
147
  });
126
148
  this.store.updateCursorState(this.observerId, CursorState.Leave);
127
149
  }
128
150
 
129
- public getFocusBox() {
130
- return this.appManager.boxManager.getFocusBox();
131
- }
132
-
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.store.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.store.updateCursor(this.observerId, {
155
- x: worldPosition.x, y: worldPosition.y, ...event
156
- });
157
- }
158
- }
159
- }
160
- }
161
-
162
151
  private setNormalCursorState() {
163
- const cursorState = this.store.getCursorState(this.observerId)
152
+ const cursorState = this.store.getCursorState(this.observerId);
164
153
  if (cursorState !== CursorState.Normal) {
165
154
  this.store.updateCursorState(this.observerId, CursorState.Normal);
166
155
  }
package/src/MainView.ts CHANGED
@@ -1,25 +1,40 @@
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
11
  private store = this.manager.store;
11
12
  private started = false;
13
+ private mainViewIsAddListener = false;
14
+ private mainView: View;
12
15
 
13
16
  constructor(
14
17
  private manager: AppManager,
15
18
  ) {
19
+ this.mainView = this.createMainView();
16
20
  emitter.once("mainViewMounted").then(() => {
21
+ this.view.callbacks.on("onCameraUpdated", this.mainViewCameraListener);
17
22
  setTimeout(() => {
18
23
  this.start();
19
24
  }, 300); // 等待 mainView 挂载完毕再进行监听,否则会触发不必要的 onSizeUpdated
20
25
  })
21
26
  }
22
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
+
23
38
  private get observerId() {
24
39
  return this.manager.displayer.observerId;
25
40
  }
@@ -54,7 +69,23 @@ export class MainViewProxy {
54
69
  }
55
70
 
56
71
  public get view(): View {
57
- 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;
58
89
  }
59
90
 
60
91
  private cameraListener = (camera: Camera) => {
@@ -64,12 +95,39 @@ export class MainViewProxy {
64
95
  }
65
96
  }
66
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
+
67
125
  private sizeListener = (size: Size) => {
68
126
  this.setMainViewSize(size);
69
127
  }
70
128
 
71
129
  public setMainViewSize = debounce(size => {
72
- this.manager.store.setMainViewSize({ ...size, id: this.observerId });
130
+ this.store.setMainViewSize({ ...size, id: this.observerId });
73
131
  }, 50);
74
132
 
75
133
  private addCameraListener() {
@@ -80,6 +138,22 @@ export class MainViewProxy {
80
138
  this.view.callbacks.off("onCameraUpdatedByDevice", this.cameraListener);
81
139
  }
82
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
+
83
157
  public moveCameraToContian(size: Size): void {
84
158
  if (!isEmpty(size)) {
85
159
  this.view.moveCameraToContain({
@@ -107,15 +181,6 @@ export class MainViewProxy {
107
181
  }
108
182
  }
109
183
 
110
- public start() {
111
- if (this.started) return;
112
- this.addCameraListener();
113
- this.manager.refresher?.add(Fields.MainViewCamera, this.cameraReaction);
114
- this.manager.refresher?.add(Fields.MainViewSize, this.sizeReaction);
115
- this.view.callbacks.on("onSizeUpdated", this.sizeListener);
116
- this.started = true;
117
- }
118
-
119
184
  public stop() {
120
185
  this.removeCameraListener();
121
186
  this.manager.refresher?.remove(Fields.MainViewCamera);
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,7 +168,7 @@ 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.18";
171
+ public version = "0.2.19-canary.0";
172
172
 
173
173
  public appListeners?: AppListeners;
174
174
 
@@ -455,7 +455,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
455
455
  * 切换 mainView 为可写
456
456
  */
457
457
  public switchMainViewToWriter(): Promise<void> | undefined {
458
- return this.appManager?.viewManager.mainViewClickHandler();
458
+ return this.appManager?.mainViewProxy.mainViewClickHandler();
459
459
  }
460
460
 
461
461
  /**
@@ -483,7 +483,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
483
483
 
484
484
  public get mainView(): View {
485
485
  if (this.appManager) {
486
- return this.appManager.viewManager.mainView;
486
+ return this.appManager.mainViewProxy.view;
487
487
  } else {
488
488
  throw new AppManagerNotInitError();
489
489
  }
@@ -491,7 +491,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
491
491
 
492
492
  public get camera(): Camera {
493
493
  if (this.appManager) {
494
- return this.appManager.viewManager.mainView.camera;
494
+ return this.appManager.mainViewProxy.view.camera;
495
495
  } else {
496
496
  throw new AppManagerNotInitError();
497
497
  }
@@ -571,21 +571,8 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
571
571
 
572
572
  private bindMainView(divElement: HTMLDivElement, disableCameraTransform: boolean) {
573
573
  if (this.appManager) {
574
- const mainView = this.appManager.viewManager.mainView;
575
- mainView.disableCameraTransform = disableCameraTransform;
576
- mainView.divElement = divElement;
574
+ this.appManager.bindMainView(divElement, disableCameraTransform);
577
575
  this.cursorManager?.setMainViewDivElement(divElement);
578
- if (!mainView.focusScenePath) {
579
- this.appManager.store.setMainViewFocusPath();
580
- }
581
- if (
582
- this.appManager.store.focus === undefined &&
583
- mainView.mode !== ViewVisionMode.Writable
584
- ) {
585
- this.appManager.viewManager.switchMainViewToWriter();
586
- }
587
- this.appManager.viewManager.addMainViewListener();
588
- emitter.emit("mainViewMounted");
589
576
  }
590
577
  }
591
578
 
@@ -616,12 +603,6 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
616
603
  }
617
604
  }
618
605
 
619
- private safeDispatchMagixEvent(event: string, payload: any) {
620
- if (this.canOperate) {
621
- (this.displayer as Room).dispatchMagixEvent(event, payload);
622
- }
623
- }
624
-
625
606
  private isDynamicPPT(scenes: SceneDefinition[]) {
626
607
  const sceneSrc = scenes[0]?.ppt?.src;
627
608
  return sceneSrc?.startsWith("pptx://");