@netless/window-manager 0.4.0-canary.21 → 0.4.0-canary.25

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/docs/api.md CHANGED
@@ -136,6 +136,7 @@ manager.setBoxState("normal") // boxState: normal | maximized | minimized
136
136
  | ------------------ | ------- | ------- | ----------------- |
137
137
  | mainView | View | | 主白板 |
138
138
  | mainViewSceneIndex | number | | 当前主白板的 SceneIndex |
139
+ | mainViewScenesLength | number | | mainView 的 scenes 长度 |
139
140
  | boxState | string | | 当前窗口状态 |
140
141
  | darkMode | boolean | | 黑夜模式 |
141
142
  | prefersColorScheme | string | | 颜色主题 |
@@ -158,3 +159,4 @@ manager.callbacks.on(events, listener)
158
159
  | prefersColorSchemeChange | string | | auto,light,dark |
159
160
  | cameraStateChange | CameraState | | |
160
161
  | focusedChange | string, undefined | | 当前 focus 的 appId,主白板时为 undefined |
162
+ | mainViewScenesLengthChange | number | | mainView scenes 添加或删除时触发 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/window-manager",
3
- "version": "0.4.0-canary.21",
3
+ "version": "0.4.0-canary.25",
4
4
  "description": "",
5
5
  "main": "dist/index.es.js",
6
6
  "module": "dist/index.es.js",
@@ -31,7 +31,7 @@
31
31
  "video.js": ">=7"
32
32
  },
33
33
  "devDependencies": {
34
- "@netless/app-docs-viewer": "^0.2.5",
34
+ "@netless/app-docs-viewer": "^0.2.6",
35
35
  "@netless/app-media-player": "0.1.0-beta.5",
36
36
  "@netless/telebox-insider": "0.2.21",
37
37
  "@rollup/plugin-commonjs": "^20.0.0",
package/src/AppManager.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import pRetry from "p-retry";
2
- import { AppAttributes, AppStatus, Events, MagixEventName } from "./constants";
2
+ import { AppAttributes, AppStatus, Events, MagixEventName, ROOT_DIR } from "./constants";
3
3
  import { AppListeners } from "./AppListener";
4
4
  import { AppProxy } from "./AppProxy";
5
5
  import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
@@ -20,8 +20,9 @@ import { store } from "./AttributesDelegate";
20
20
  import { ViewManager } from "./View/ViewManager";
21
21
  import type { ReconnectRefresher } from "./ReconnectRefresher";
22
22
  import type { BoxManager } from "./BoxManager";
23
- import type { Displayer, DisplayerState, Room } from "white-web-sdk";
23
+ import type { Displayer, DisplayerState, Room, ScenesCallbacksNode } from "white-web-sdk";
24
24
  import type { AddAppParams, BaseInsertParams, TeleBoxRect, EmitterEvent } from "./index";
25
+ import { appRegister } from "./Register";
25
26
 
26
27
  export class AppManager {
27
28
  public displayer: Displayer;
@@ -32,12 +33,14 @@ export class AppManager {
32
33
  public mainViewProxy: MainViewProxy;
33
34
  public refresher?: ReconnectRefresher;
34
35
  public isReplay = this.windowManger.isReplay;
36
+ public mainViewScenesLength = 0;
35
37
 
36
38
  private appListeners: AppListeners;
37
39
  public boxManager?: BoxManager;
38
40
 
39
41
  private _prevSceneIndex: number | undefined;
40
42
  private _prevFocused: string | undefined;
43
+ private callbacksNode: ScenesCallbacksNode | null;
41
44
 
42
45
  constructor(public windowManger: WindowManager) {
43
46
  this.displayer = windowManger.displayer;
@@ -68,17 +71,30 @@ export class AppManager {
68
71
  });
69
72
  }
70
73
  emitter.on("removeScenes", scenePath => {
71
- if (scenePath === "/") {
72
- this.setMainViewScenePath("/");
74
+ if (scenePath === ROOT_DIR) {
75
+ this.setMainViewScenePath(ROOT_DIR);
73
76
  return;
74
77
  }
75
78
  const mainViewScenePath = this.store.getMainViewScenePath();
76
79
  if (this.room && mainViewScenePath) {
77
80
  if (mainViewScenePath === scenePath) {
78
- this.setMainViewScenePath("/");
81
+ this.setMainViewScenePath(ROOT_DIR);
79
82
  }
80
83
  }
81
84
  });
85
+ this.callbacksNode = this.displayer.createScenesCallback(ROOT_DIR, {
86
+ onAddScene: scenesCallback => {
87
+ this.mainViewScenesLength = scenesCallback.scenes.length;
88
+ callbacks.emit("mainViewScenesLengthChange", this.mainViewScenesLength);
89
+ },
90
+ onRemoveScene: scenesCallback => {
91
+ this.mainViewScenesLength = scenesCallback.scenes.length;
92
+ callbacks.emit("mainViewScenesLengthChange", this.mainViewScenesLength);
93
+ },
94
+ });
95
+ if (this.callbacksNode) {
96
+ this.mainViewScenesLength = this.callbacksNode.scenes.length;
97
+ }
82
98
  }
83
99
 
84
100
  private get eventName() {
@@ -111,6 +127,15 @@ export class AppManager {
111
127
  return this.room?.uid || "";
112
128
  }
113
129
 
130
+ public getMainViewSceneDir() {
131
+ const scenePath = this.store.getMainViewScenePath();
132
+ if (scenePath) {
133
+ return parseSceneDir(scenePath);
134
+ } else {
135
+ throw new Error("[WindowManager]: mainViewSceneDir not found");
136
+ }
137
+ }
138
+
114
139
  private async onCreated() {
115
140
  await this.attributesUpdateCallback(this.attributes.apps);
116
141
  this.boxManager?.updateManagerRect();
@@ -161,6 +186,10 @@ export class AppManager {
161
186
  const focused = get(this.attributes, "focus");
162
187
  if (this._prevFocused !== focused) {
163
188
  this.boxManager?.focusBox({ appId: focused });
189
+ const appProxy = this.appProxies.get(focused);
190
+ if (appProxy) {
191
+ appRegister.notifyApp(appProxy.kind, "focus", { appId: focused });
192
+ }
164
193
  callbacks.emit("focusedChange", focused);
165
194
  this._prevFocused = focused;
166
195
  }
@@ -384,6 +413,10 @@ export class AppManager {
384
413
  public async setMainViewScenePath(scenePath: string) {
385
414
  if (this.room) {
386
415
  const scenePathType = this.displayer.scenePathType(scenePath);
416
+ const sceneDir = parseSceneDir(scenePath);
417
+ if (sceneDir !== ROOT_DIR) {
418
+ throw new Error(`[WindowManager]: main view scenePath must in root dir "/"`);
419
+ }
387
420
  if (scenePathType === ScenePathType.None) {
388
421
  throw new Error(`[WindowManager]: ${scenePath} not valid scene`);
389
422
  } else if (scenePathType === ScenePathType.Page) {
@@ -549,6 +582,7 @@ export class AppManager {
549
582
  this.refresher?.destroy();
550
583
  this.mainViewProxy.destroy();
551
584
  callbacks.clearListeners();
585
+ this.callbacksNode?.dispose();
552
586
  this._prevSceneIndex = undefined;
553
587
  }
554
588
  }
package/src/AppProxy.ts CHANGED
@@ -7,7 +7,7 @@ import { BoxManagerNotFoundError } from "./Utils/error";
7
7
  import { debounce, get } from "lodash";
8
8
  import { emitter } from "./index";
9
9
  import { Fields } from "./AttributesDelegate";
10
- import { getScenePath, removeScenes, setScenePath, setViewFocusScenePath } from "./Utils/Common";
10
+ import { entireScenes, getScenePath, removeScenes, setScenePath, setViewFocusScenePath } from "./Utils/Common";
11
11
  import { log } from "./Utils/log";
12
12
  import type {
13
13
  AppEmitterEvent,
@@ -22,6 +22,7 @@ import type { NetlessApp } from "./typings";
22
22
  import type { ReadonlyTeleBox } from "@netless/telebox-insider";
23
23
 
24
24
  export class AppProxy {
25
+ public kind: string;
25
26
  public id: string;
26
27
  public scenePath?: string;
27
28
  public appEmitter: Emittery<AppEmitterEvent>;
@@ -32,7 +33,7 @@ export class AppProxy {
32
33
  private appProxies = this.manager.appProxies;
33
34
  private viewManager = this.manager.viewManager;
34
35
  private store = this.manager.store;
35
- private kind: string;
36
+
36
37
  public isAddApp: boolean;
37
38
  private status: "normal" | "destroyed" = "normal";
38
39
  private stateKey: string;
@@ -66,7 +67,7 @@ export class AppProxy {
66
67
  if (options) {
67
68
  this.scenePath = options.scenePath;
68
69
  if (this.appAttributes?.isDynamicPPT && this.scenePath) {
69
- this.scenes = this.manager.displayer.entireScenes()[this.scenePath];
70
+ this.scenes = entireScenes(this.manager.displayer)[this.scenePath];
70
71
  } else {
71
72
  this.scenes = options.scenes;
72
73
  }
@@ -133,19 +134,10 @@ export class AppProxy {
133
134
  };
134
135
  }
135
136
 
136
- private focusApp() {
137
- this.focusBox();
138
- this.store.setMainViewFocusPath(this.manager.mainView);
139
- }
140
-
141
137
  public get box(): ReadonlyTeleBox | undefined {
142
138
  return this.boxManager?.getBox(this.id);
143
139
  }
144
140
 
145
- public focusBox() {
146
- this.boxManager?.focusBox({ appId: this.id });
147
- }
148
-
149
141
  private async setupApp(
150
142
  appId: string,
151
143
  skipUpdate: boolean,
@@ -187,8 +179,7 @@ export class AppProxy {
187
179
  });
188
180
  if (this.isAddApp && this.box) {
189
181
  this.store.updateAppState(appId, AppAttributes.ZIndex, this.box.zIndex);
190
- this.store.setAppFocus(appId, true);
191
- this.focusBox();
182
+ this.boxManager.focusBox({ appId }, false);
192
183
  }
193
184
  } catch (error: any) {
194
185
  console.error(error);
@@ -42,6 +42,7 @@ export class CursorManager {
42
42
  if (payload.state === CursorState.Leave) {
43
43
  cursorInstance.leave();
44
44
  } else {
45
+ cursorInstance.setMember();
45
46
  cursorInstance.move(payload.position);
46
47
  }
47
48
  });
@@ -18,7 +18,7 @@ export const getScript = async (url: string): Promise<string> => {
18
18
  };
19
19
 
20
20
  export const executeScript = (text: string, appName: string): NetlessApp => {
21
- let result = Function(text + `;return ${appName}`)();
21
+ let result = Function(text + `\n;return ${appName}`)();
22
22
  if (typeof result === "undefined") {
23
23
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
24
24
  // @ts-ignore
@@ -1,11 +1,13 @@
1
1
  import { appRegister } from "../Register";
2
- import { debounce } from "lodash";
2
+ import { debounce, memoize } from "lodash";
3
3
  import { emitter } from "../index";
4
4
  import { ScenePathType } from "white-web-sdk";
5
5
  import { v4 } from "uuid";
6
6
  import type { PublicEvent } from "../index";
7
7
  import type { Displayer, ViewVisionMode, Room, View } from "white-web-sdk";
8
8
  import type Emittery from "emittery";
9
+ import { log } from "./log";
10
+ import { ROOT_DIR } from "../constants";
9
11
 
10
12
  export const genAppId = async (kind: string) => {
11
13
  const impl = await appRegister.appClasses.get(kind)?.();
@@ -91,7 +93,7 @@ export const makeValidScenePath = (displayer: Displayer, scenePath: string, inde
91
93
  const scene = scenes[index];
92
94
  if (!scene) return;
93
95
  const firstSceneName = scene.name;
94
- if (scenePath === "/") {
96
+ if (scenePath === ROOT_DIR) {
95
97
  return `/${firstSceneName}`;
96
98
  } else {
97
99
  return `${scenePath}/${firstSceneName}`;
@@ -99,9 +101,16 @@ export const makeValidScenePath = (displayer: Displayer, scenePath: string, inde
99
101
  };
100
102
 
101
103
  export const entireScenes = (displayer: Displayer) => {
102
- return displayer.entireScenes();
104
+ // 缓存 entireScenes 结果, 避免频繁调用
105
+ const cacheKey = Math.round(Date.now() / 1000);
106
+ return invokeEntireScenes(cacheKey, displayer);
103
107
  };
104
108
 
109
+ const invokeEntireScenes = memoize((cacheKey: number, displayer: Displayer) => {
110
+ log("invokeEntireScenes", cacheKey);
111
+ return displayer.entireScenes();
112
+ });
113
+
105
114
  export const isValidScenePath = (scenePath: string) => {
106
115
  return scenePath.startsWith("/");
107
116
  };
package/src/constants.ts CHANGED
@@ -46,3 +46,5 @@ export const MIN_HEIGHT = 340 / 720;
46
46
  export const SET_SCENEPATH_DELAY = 100; // 设置 scenePath 的延迟事件
47
47
 
48
48
  export const DEFAULT_CONTAINER_RATIO = 9 / 16;
49
+
50
+ export const ROOT_DIR = "/";
package/src/index.ts CHANGED
@@ -19,9 +19,9 @@ import "@netless/telebox-insider/dist/style.css";
19
19
  import {
20
20
  addEmitterOnceListener,
21
21
  ensureValidScenePath,
22
+ entireScenes,
22
23
  getVersionNumber,
23
24
  isValidScenePath,
24
- parseSceneDir,
25
25
  wait,
26
26
  } from "./Utils/Common";
27
27
  import type { TELE_BOX_STATE, BoxManager } from "./BoxManager";
@@ -157,6 +157,7 @@ export type PublicEvent = {
157
157
  mainViewScenePathChange: string;
158
158
  mainViewSceneIndexChange: number;
159
159
  focusedChange: string | undefined;
160
+ mainViewScenesLengthChange: number;
160
161
  };
161
162
 
162
163
  export type MountParams = {
@@ -447,11 +448,11 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
447
448
  if (scenePath && scenes && scenes.length > 0) {
448
449
  if (this.isDynamicPPT(scenes)) {
449
450
  isDynamicPPT = true;
450
- if (!this.displayer.entireScenes()[scenePath]) {
451
+ if (!entireScenes(this.displayer)[scenePath]) {
451
452
  this.room?.putScenes(scenePath, scenes);
452
453
  }
453
454
  } else {
454
- if (!this.displayer.entireScenes()[scenePath]) {
455
+ if (!entireScenes(this.displayer)[scenePath]) {
455
456
  this.room?.putScenes(scenePath, [{ name: scenes[0].name }]);
456
457
  }
457
458
  }
@@ -618,11 +619,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
618
619
  }
619
620
 
620
621
  public get mainViewSceneDir(): string {
621
- const scenePath = this.appManager?.store.getMainViewScenePath();
622
- if (scenePath) {
623
- return parseSceneDir(scenePath);
622
+ if (this.appManager) {
623
+ return this.appManager?.getMainViewSceneDir();
624
624
  } else {
625
- throw new Error("[WindowManager]: mainViewSceneDir not found");
625
+ throw new AppManagerNotInitError();
626
626
  }
627
627
  }
628
628
 
@@ -630,6 +630,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
630
630
  return this.boxManager?.getTopBox()?.id;
631
631
  }
632
632
 
633
+ public get mainViewScenesLength(): number {
634
+ return this.appManager?.mainViewScenesLength || 0;
635
+ }
636
+
633
637
  /**
634
638
  * 查询所有的 App
635
639
  */
@@ -770,10 +774,6 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
770
774
  }
771
775
  }
772
776
  }
773
-
774
- private _removeScenes = (scenePath: string) => {
775
- this.room.removeScenes(scenePath);
776
- };
777
777
  }
778
778
 
779
779
  setupBuiltin();