@netless/window-manager 0.4.0-canary.24 → 0.4.0-canary.28

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
@@ -11,6 +11,7 @@
11
11
  - [`closeApp`](#closeApp)
12
12
  - [`setMainViewSceneIndex`](#setMainViewSceneIndex)
13
13
  - [`setBoxState`](#setBoxState)
14
+ - [`cleanCurrentScene`](#cleanCurrentScene)
14
15
  - [实例属性](#prototypes)
15
16
  - [事件回调](#events)
16
17
 
@@ -128,6 +129,14 @@ manager.setMainViewSceneIndex(1)
128
129
  manager.setBoxState("normal") // boxState: normal | maximized | minimized
129
130
  ```
130
131
 
132
+ <h3 id="cleanCurrentScene">cleanCurrentScene</h3>
133
+
134
+ > 清除当前 focus 的 view 的笔迹
135
+
136
+ ```ts
137
+ manager.cleanCurrentScene()
138
+ ```
139
+
131
140
  <br>
132
141
 
133
142
  <h2 id="prototypes">实例属性</h2>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/window-manager",
3
- "version": "0.4.0-canary.24",
3
+ "version": "0.4.0-canary.28",
4
4
  "description": "",
5
5
  "main": "dist/index.es.js",
6
6
  "module": "dist/index.es.js",
@@ -33,7 +33,7 @@
33
33
  "devDependencies": {
34
34
  "@netless/app-docs-viewer": "^0.2.6",
35
35
  "@netless/app-media-player": "0.1.0-beta.5",
36
- "@netless/telebox-insider": "0.2.21",
36
+ "@netless/telebox-insider": "0.2.22",
37
37
  "@rollup/plugin-commonjs": "^20.0.0",
38
38
  "@rollup/plugin-node-resolve": "^13.0.4",
39
39
  "@rollup/plugin-url": "^6.1.0",
@@ -58,6 +58,6 @@
58
58
  "typescript": "^4.3.5",
59
59
  "video.js": "^7.14.3",
60
60
  "vite": "^2.5.3",
61
- "white-web-sdk": "^2.16.1"
61
+ "white-web-sdk": "^2.16.3"
62
62
  }
63
63
  }
package/src/AppManager.ts CHANGED
@@ -1,9 +1,15 @@
1
- import pRetry from "p-retry";
2
1
  import { AppAttributes, AppStatus, Events, MagixEventName, ROOT_DIR } from "./constants";
3
2
  import { AppListeners } from "./AppListener";
4
3
  import { AppProxy } from "./AppProxy";
4
+ import { appRegister } from "./Register";
5
5
  import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
6
- import { callbacks, emitter, WindowManager, reconnectRefresher } from "./index";
6
+ import { callbacks, emitter, reconnectRefresher, WindowManager } from "./index";
7
+ import { get, isInteger, orderBy } from "lodash";
8
+ import { log } from "./Utils/log";
9
+ import { MainViewProxy } from "./View/MainView";
10
+ import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
11
+ import { store } from "./AttributesDelegate";
12
+ import { ViewManager } from "./View/ViewManager";
7
13
  import {
8
14
  entireScenes,
9
15
  genAppId,
@@ -12,17 +18,11 @@ import {
12
18
  setScenePath,
13
19
  setViewFocusScenePath,
14
20
  } from "./Utils/Common";
15
- import { log } from "./Utils/log";
16
- import { MainViewProxy } from "./View/MainView";
17
- import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
18
- import { get, isInteger, sortBy } from "lodash";
19
- import { store } from "./AttributesDelegate";
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 , ScenesCallbacksNode } 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
+ import { AppCreateQueue } from "./Utils/AppCreateQueue";
26
26
 
27
27
  export class AppManager {
28
28
  public displayer: Displayer;
@@ -41,6 +41,7 @@ export class AppManager {
41
41
  private _prevSceneIndex: number | undefined;
42
42
  private _prevFocused: string | undefined;
43
43
  private callbacksNode: ScenesCallbacksNode | null;
44
+ private appCreateQueue = new AppCreateQueue();
44
45
 
45
46
  constructor(public windowManger: WindowManager) {
46
47
  this.displayer = windowManger.displayer;
@@ -83,11 +84,11 @@ export class AppManager {
83
84
  }
84
85
  });
85
86
  this.callbacksNode = this.displayer.createScenesCallback(ROOT_DIR, {
86
- onAddScene: (scenesCallback) => {
87
+ onAddScene: scenesCallback => {
87
88
  this.mainViewScenesLength = scenesCallback.scenes.length;
88
89
  callbacks.emit("mainViewScenesLengthChange", this.mainViewScenesLength);
89
90
  },
90
- onRemoveScene: (scenesCallback) => {
91
+ onRemoveScene: scenesCallback => {
91
92
  this.mainViewScenesLength = scenesCallback.scenes.length;
92
93
  callbacks.emit("mainViewScenesLengthChange", this.mainViewScenesLength);
93
94
  },
@@ -126,7 +127,7 @@ export class AppManager {
126
127
  public get uid() {
127
128
  return this.room?.uid || "";
128
129
  }
129
-
130
+
130
131
  public getMainViewSceneDir() {
131
132
  const scenePath = this.store.getMainViewScenePath();
132
133
  if (scenePath) {
@@ -185,9 +186,18 @@ export class AppManager {
185
186
  return autorun(() => {
186
187
  const focused = get(this.attributes, "focus");
187
188
  if (this._prevFocused !== focused) {
188
- this.boxManager?.focusBox({ appId: focused });
189
189
  callbacks.emit("focusedChange", focused);
190
190
  this._prevFocused = focused;
191
+ if (focused !== undefined) {
192
+ this.boxManager?.focusBox({ appId: focused });
193
+ // 确保 focus 修改的时候, appProxy 已经创建
194
+ setTimeout(() => {
195
+ const appProxy = this.appProxies.get(focused);
196
+ if (appProxy) {
197
+ appRegister.notifyApp(appProxy.kind, "focus", { appId: focused });
198
+ }
199
+ }, 0);
200
+ }
191
201
  }
192
202
  });
193
203
  });
@@ -219,19 +229,18 @@ export class AppManager {
219
229
  createdAt: apps[appId].createdAt,
220
230
  };
221
231
  });
222
- for (const { id } of sortBy(appsWithCreatedAt, "createdAt")) {
232
+ for (const { id } of orderBy(appsWithCreatedAt, "createdAt", "asc")) {
223
233
  if (!this.appProxies.has(id) && !this.appStatus.has(id)) {
224
234
  const app = apps[id];
225
235
 
226
- pRetry(
227
- async () => {
228
- this.appStatus.set(id, AppStatus.StartCreate);
229
- // 防御 appAttributes 有可能为 undefined 的情况,这里做一个重试
230
- const appAttributes = this.attributes[id];
231
- if (!appAttributes) {
232
- throw new Error("appAttributes is undefined");
233
- }
234
- await this.baseInsertApp(
236
+ this.appStatus.set(id, AppStatus.StartCreate);
237
+ try {
238
+ const appAttributes = this.attributes[id];
239
+ if (!appAttributes) {
240
+ throw new Error("appAttributes is undefined");
241
+ }
242
+ this.appCreateQueue.push(() => {
243
+ return this.baseInsertApp(
235
244
  {
236
245
  kind: app.kind,
237
246
  options: app.options,
@@ -240,13 +249,11 @@ export class AppManager {
240
249
  id,
241
250
  false
242
251
  );
243
- this.focusByAttributes(apps);
244
- },
245
- { retries: 3 }
246
- ).catch(err => {
247
- console.warn(`[WindowManager]: Insert App Error`, err);
248
- this.appStatus.delete(id);
249
- });
252
+ });
253
+ this.focusByAttributes(apps);
254
+ } catch (error) {
255
+ console.warn(`[WindowManager]: Insert App Error`, error);
256
+ }
250
257
  }
251
258
  }
252
259
  }
@@ -432,7 +439,7 @@ export class AppManager {
432
439
  this.safeSetAttributes({ _mainScenePath: scenePath });
433
440
  this.store.setMainViewFocusPath(this.mainView);
434
441
  this.updateSceneIndex();
435
- this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath: scenePath });
442
+ this.dispatchSetMainViewScenePath(scenePath);
436
443
  }
437
444
  }
438
445
 
@@ -462,9 +469,7 @@ export class AppManager {
462
469
  if (success) {
463
470
  this.store.setMainViewScenePath(scenePath);
464
471
  this.safeSetAttributes({ _mainSceneIndex: index });
465
- this.dispatchInternalEvent(Events.SetMainViewScenePath, {
466
- nextScenePath: scenePath,
467
- });
472
+ this.dispatchSetMainViewScenePath(scenePath);
468
473
  }
469
474
  } else {
470
475
  throw new Error(`[WindowManager]: ${sceneDir}: ${index} not valid index`);
@@ -473,6 +478,12 @@ export class AppManager {
473
478
  }
474
479
  }
475
480
 
481
+ private dispatchSetMainViewScenePath(scenePath: string): void {
482
+ this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath: scenePath });
483
+ // 兼容 15 的 SDK, 需要 room 的当前 ScenePath
484
+ setScenePath(this.room, scenePath);
485
+ }
486
+
476
487
  public getAppInitPath(appId: string): string | undefined {
477
488
  const attrs = this.store.getAppAttributes(appId);
478
489
  if (attrs) {
@@ -498,10 +509,6 @@ export class AppManager {
498
509
  }
499
510
  case "focus": {
500
511
  this.windowManger.safeSetAttributes({ focus: payload.appId });
501
- const appProxy = this.appProxies.get(payload.appId);
502
- if (appProxy) {
503
- appRegister.notifyApp(appProxy.kind, "focus", { appId: payload.appId });
504
- }
505
512
  break;
506
513
  }
507
514
  case "resize": {
@@ -583,6 +590,7 @@ export class AppManager {
583
590
  this.mainViewProxy.destroy();
584
591
  callbacks.clearListeners();
585
592
  this.callbacksNode?.dispose();
593
+ this.appCreateQueue.destroy();
586
594
  this._prevSceneIndex = undefined;
587
595
  }
588
596
  }
package/src/AppProxy.ts CHANGED
@@ -165,7 +165,7 @@ export class AppProxy {
165
165
  // 延迟执行 setup, 防止初始化的属性没有更新成功
166
166
  const result = await app.setup(context);
167
167
  this.appResult = result;
168
- appRegister.notifyApp(app.kind, "created", { appId, result });
168
+ appRegister.notifyApp(this.kind, "created", { appId, result });
169
169
  this.afterSetupApp(boxInitState);
170
170
  this.fixMobileSize();
171
171
  }, 50);
@@ -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
  });
package/src/Helper.ts CHANGED
@@ -1,3 +1,7 @@
1
+ import { getVersionNumber } from "./Utils/Common";
2
+ import { REQUIRE_VERSION } from "./constants";
3
+ import { WhiteVersion } from "white-web-sdk";
4
+ import { WhiteWebSDKInvalidError } from "./Utils/error";
1
5
  import { WindowManager } from "./index";
2
6
 
3
7
  export const setupWrapper = (
@@ -27,4 +31,11 @@ export const setupWrapper = (
27
31
  WindowManager.wrapper = wrapper;
28
32
 
29
33
  return { playground, wrapper, sizer, mainViewElement };
30
- };
34
+ };
35
+
36
+ export const checkVersion = () => {
37
+ const version = getVersionNumber(WhiteVersion);
38
+ if (version < getVersionNumber(REQUIRE_VERSION)) {
39
+ throw new WhiteWebSDKInvalidError(REQUIRE_VERSION);
40
+ }
41
+ };
@@ -0,0 +1,54 @@
1
+ import type { AppProxy } from "../AppProxy";
2
+
3
+ export type Invoker = () => Promise<AppProxy | undefined>;
4
+
5
+ export class AppCreateQueue {
6
+ private list: Invoker[] = [];
7
+ private currentInvoker: Invoker | undefined;
8
+ private timer: number | undefined;
9
+
10
+ private initInterval() {
11
+ return setInterval(() => {
12
+ this.invoke();
13
+ }, 50);
14
+ }
15
+
16
+ public push(item: Invoker) {
17
+ this.list.push(item);
18
+ this.invoke();
19
+ if (this.timer === undefined && this.list.length > 0) {
20
+ this.timer = this.initInterval();
21
+ }
22
+ }
23
+
24
+ public invoke() {
25
+ if (this.list.length === 0) {
26
+ return;
27
+ }
28
+ if (this.currentInvoker !== undefined) {
29
+ return;
30
+ }
31
+
32
+ const item = this.list.shift();
33
+ if (item) {
34
+ this.currentInvoker = item;
35
+ item()
36
+ .then(() => {
37
+ this.currentInvoker = undefined;
38
+ if (this.list.length === 0) {
39
+ clearInterval(this.timer);
40
+ }
41
+ })
42
+ .catch(error => {
43
+ console.error(`[WindowManager]: create app error: ${error.message}`);
44
+ clearInterval(this.timer);
45
+ });
46
+ }
47
+ }
48
+
49
+ public destroy() {
50
+ if (this.timer) {
51
+ clearInterval(this.timer);
52
+ }
53
+ }
54
+ }
@@ -1,12 +1,11 @@
1
1
  import { appRegister } from "../Register";
2
- import { debounce, memoize } from "lodash";
2
+ import { debounce } 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
9
  import { ROOT_DIR } from "../constants";
11
10
 
12
11
  export const genAppId = async (kind: string) => {
@@ -101,15 +100,9 @@ export const makeValidScenePath = (displayer: Displayer, scenePath: string, inde
101
100
  };
102
101
 
103
102
  export const entireScenes = (displayer: Displayer) => {
104
- // 缓存 entireScenes 结果, 避免频繁调用
105
- const cacheKey = Math.round(Date.now() / 1000);
106
- return invokeEntireScenes(cacheKey, displayer);
103
+ return displayer.entireScenes();
107
104
  };
108
105
 
109
- const invokeEntireScenes = memoize((cacheKey: number, displayer: Displayer) => {
110
- log("invokeEntireScenes", cacheKey);
111
- return displayer.entireScenes();
112
- });
113
106
 
114
107
  export const isValidScenePath = (scenePath: string) => {
115
108
  return scenePath.startsWith("/");
@@ -4,11 +4,12 @@ import type { WindowManager } from "../index";
4
4
  import type { Camera, Room, Player, PlayerSeekingResult } from "white-web-sdk";
5
5
 
6
6
  // 修改多窗口状态下一些失效的方法实现到 manager 的 mainview 上, 降低迁移成本
7
- export const replaceRoomFunction = (room: Room, manager: WindowManager) => {
7
+ export const replaceRoomFunction = (room: Room | Player, manager: WindowManager) => {
8
8
  if (isPlayer(room)) {
9
9
  const player = room as unknown as Player;
10
10
  delegateSeekToProgressTime(player);
11
11
  } else {
12
+ room = room as unknown as Room;
12
13
  const descriptor = Object.getOwnPropertyDescriptor(room, "disableCameraTransform");
13
14
  if (descriptor) return;
14
15
  Object.defineProperty(room, "disableCameraTransform", {
package/src/index.ts CHANGED
@@ -2,25 +2,25 @@ import Emittery from "emittery";
2
2
  import pRetry from "p-retry";
3
3
  import { AppManager } from "./AppManager";
4
4
  import { appRegister } from "./Register";
5
+ import { checkVersion, setupWrapper } from "./Helper";
5
6
  import { ContainerResizeObserver } from "./ContainerResizeObserver";
6
7
  import { createBoxManager } from "./BoxManager";
7
8
  import { CursorManager } from "./Cursor";
8
- import { DEFAULT_CONTAINER_RATIO, Events, REQUIRE_VERSION } from "./constants";
9
+ import { DEFAULT_CONTAINER_RATIO, Events } from "./constants";
9
10
  import { Fields } from "./AttributesDelegate";
10
11
  import { initDb } from "./Register/storage";
12
+ import { InvisiblePlugin, isPlayer, isRoom, RoomPhase, ViewMode } from "white-web-sdk";
11
13
  import { isNull, isObject } from "lodash";
12
14
  import { log } from "./Utils/log";
13
15
  import { ReconnectRefresher } from "./ReconnectRefresher";
14
16
  import { replaceRoomFunction } from "./Utils/RoomHacker";
15
17
  import { setupBuiltin } from "./BuiltinApps";
16
- import { setupWrapper } from "./Helper";
17
18
  import "./style.css";
18
19
  import "@netless/telebox-insider/dist/style.css";
19
20
  import {
20
21
  addEmitterOnceListener,
21
22
  ensureValidScenePath,
22
23
  entireScenes,
23
- getVersionNumber,
24
24
  isValidScenePath,
25
25
  wait,
26
26
  } from "./Utils/Common";
@@ -30,17 +30,8 @@ import {
30
30
  AppManagerNotInitError,
31
31
  InvalidScenePath,
32
32
  ParamsInvalidError,
33
- WhiteWebSDKInvalidError,
34
33
  } from "./Utils/error";
35
34
  import type { Apps, Position } from "./AttributesDelegate";
36
- import {
37
- InvisiblePlugin,
38
- isPlayer,
39
- isRoom,
40
- RoomPhase,
41
- ViewMode,
42
- WhiteVersion,
43
- } from "white-web-sdk";
44
35
  import type {
45
36
  Displayer,
46
37
  SceneDefinition,
@@ -54,6 +45,7 @@ import type {
54
45
  Rectangle,
55
46
  ViewVisionMode,
56
47
  CameraState,
48
+ Player,
57
49
  } from "white-web-sdk";
58
50
  import type { AppListeners } from "./AppListener";
59
51
  import type { NetlessApp, RegisterParams } from "./typings";
@@ -161,7 +153,7 @@ export type PublicEvent = {
161
153
  };
162
154
 
163
155
  export type MountParams = {
164
- room: Room;
156
+ room: Room | Player;
165
157
  container?: HTMLElement;
166
158
  /** 白板高宽比例, 默认为 9 / 16 */
167
159
  containerSizeRatio?: number;
@@ -223,7 +215,8 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
223
215
  const cursor = params.cursor;
224
216
  WindowManager.params = params;
225
217
 
226
- this.checkVersion();
218
+ checkVersion();
219
+ let manager: WindowManager | undefined = undefined;
227
220
  if (isRoom(room)) {
228
221
  if (room.phase !== RoomPhase.Connected) {
229
222
  throw new Error("[WindowManager]: Room only Connected can be mount");
@@ -232,11 +225,12 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
232
225
  // redo undo 需要设置这个属性
233
226
  room.disableSerialization = false;
234
227
  }
228
+ manager = await this.initManager(room);
235
229
  }
236
230
  if (WindowManager.isCreated) {
237
231
  throw new Error("[WindowManager]: Already created cannot be created again");
238
232
  }
239
- let manager = await this.initManager(room);
233
+
240
234
  this.debug = Boolean(debug);
241
235
  log("Already insert room", manager);
242
236
 
@@ -247,7 +241,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
247
241
  } else {
248
242
  await pRetry(
249
243
  async count => {
250
- manager = await this.initManager(room);
244
+ manager = (await room.getInvisiblePlugin(WindowManager.kind)) as WindowManager;
251
245
  if (!manager) {
252
246
  log(`manager is empty. retrying ${count}`);
253
247
  throw new Error();
@@ -257,6 +251,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
257
251
  );
258
252
  }
259
253
 
254
+ if (!manager) {
255
+ throw new Error("[WindowManager]: create manager failed");
256
+ }
257
+
260
258
  if (containerSizeRatio) {
261
259
  WindowManager.containerSizeRatio = containerSizeRatio;
262
260
  }
@@ -742,18 +740,20 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
742
740
  this.appManager?.boxManager?.setPrefersColorScheme(scheme);
743
741
  }
744
742
 
743
+ public cleanCurrentScene(): void {
744
+ const focused = this.focused;
745
+ if (focused) {
746
+ this.appManager?.focusApp?.view?.cleanCurrentScene();
747
+ } else {
748
+ this.mainView.cleanCurrentScene();
749
+ }
750
+ }
751
+
745
752
  private isDynamicPPT(scenes: SceneDefinition[]) {
746
753
  const sceneSrc = scenes[0]?.ppt?.src;
747
754
  return sceneSrc?.startsWith("pptx://");
748
755
  }
749
756
 
750
- private static checkVersion() {
751
- const version = getVersionNumber(WhiteVersion);
752
- if (version < getVersionNumber(REQUIRE_VERSION)) {
753
- throw new WhiteWebSDKInvalidError(REQUIRE_VERSION);
754
- }
755
- }
756
-
757
757
  private async ensureAttributes() {
758
758
  if (isNull(this.attributes)) {
759
759
  await wait(50);
@@ -774,10 +774,6 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
774
774
  }
775
775
  }
776
776
  }
777
-
778
- private _removeScenes = (scenePath: string) => {
779
- this.room.removeScenes(scenePath);
780
- };
781
777
  }
782
778
 
783
779
  setupBuiltin();