@netless/window-manager 0.4.0-canary.3 → 0.4.0-canary.7

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.
Files changed (66) hide show
  1. package/dist/index.es.js +1 -1
  2. package/dist/index.es.js.map +1 -1
  3. package/dist/index.umd.js +1 -1
  4. package/dist/index.umd.js.map +1 -1
  5. package/dist/src/App/Storage/StorageEvent.d.ts +8 -0
  6. package/dist/src/App/Storage/index.d.ts +26 -0
  7. package/dist/src/App/Storage/typings.d.ts +21 -0
  8. package/dist/src/App/Storage/utils.d.ts +5 -0
  9. package/dist/{AppContext.d.ts → src/AppContext.d.ts} +2 -0
  10. package/dist/{AppListener.d.ts → src/AppListener.d.ts} +0 -1
  11. package/dist/{AppManager.d.ts → src/AppManager.d.ts} +4 -5
  12. package/dist/{AppProxy.d.ts → src/AppProxy.d.ts} +2 -3
  13. package/dist/{AttributesDelegate.d.ts → src/AttributesDelegate.d.ts} +0 -0
  14. package/dist/{Base → src/Base}/Context.d.ts +0 -1
  15. package/dist/{Base → src/Base}/index.d.ts +0 -0
  16. package/dist/{BoxManager.d.ts → src/BoxManager.d.ts} +2 -1
  17. package/dist/src/BuiltinApps.d.ts +6 -0
  18. package/dist/src/ContainerResizeObserver.d.ts +10 -0
  19. package/dist/{Cursor → src/Cursor}/Cursor.d.ts +0 -0
  20. package/dist/{Cursor → src/Cursor}/icons.d.ts +0 -0
  21. package/dist/{Cursor → src/Cursor}/index.d.ts +0 -0
  22. package/dist/src/Helper.d.ts +6 -0
  23. package/dist/{ReconnectRefresher.d.ts → src/ReconnectRefresher.d.ts} +0 -1
  24. package/dist/{Register → src/Register}/index.d.ts +0 -0
  25. package/dist/{Register → src/Register}/loader.d.ts +0 -0
  26. package/dist/{Register → src/Register}/storage.d.ts +0 -0
  27. package/dist/{Utils → src/Utils}/Common.d.ts +3 -1
  28. package/dist/{Utils → src/Utils}/Reactive.d.ts +1 -1
  29. package/dist/{Utils → src/Utils}/RoomHacker.d.ts +0 -0
  30. package/dist/{Utils → src/Utils}/error.d.ts +0 -0
  31. package/dist/{Utils → src/Utils}/log.d.ts +0 -0
  32. package/dist/{MainView.d.ts → src/View/MainView.d.ts} +2 -4
  33. package/dist/src/View/ViewManager.d.ts +13 -0
  34. package/dist/{constants.d.ts → src/constants.d.ts} +0 -5
  35. package/dist/{index.d.ts → src/index.d.ts} +4 -8
  36. package/dist/{typings.d.ts → src/typings.d.ts} +1 -0
  37. package/dist/style.css +1 -1
  38. package/package.json +3 -3
  39. package/src/App/Storage/StorageEvent.ts +21 -0
  40. package/src/App/Storage/index.ts +243 -0
  41. package/src/App/Storage/typings.ts +21 -0
  42. package/src/App/Storage/utils.ts +17 -0
  43. package/src/AppContext.ts +9 -1
  44. package/src/AppListener.ts +0 -8
  45. package/src/AppManager.ts +33 -28
  46. package/src/AppProxy.ts +14 -36
  47. package/src/Base/Context.ts +0 -4
  48. package/src/BoxManager.ts +9 -7
  49. package/src/BuiltinApps.ts +24 -0
  50. package/src/ContainerResizeObserver.ts +62 -0
  51. package/src/Helper.ts +30 -0
  52. package/src/ReconnectRefresher.ts +0 -5
  53. package/src/Utils/Common.ts +35 -13
  54. package/src/Utils/Reactive.ts +9 -3
  55. package/src/{MainView.ts → View/MainView.ts} +7 -25
  56. package/src/View/ViewManager.ts +53 -0
  57. package/src/constants.ts +0 -2
  58. package/src/index.ts +20 -69
  59. package/src/style.css +6 -0
  60. package/src/typings.ts +1 -0
  61. package/dist/Utils/CameraStore.d.ts +0 -15
  62. package/dist/ViewManager.d.ts +0 -29
  63. package/dist/sdk.d.ts +0 -14
  64. package/src/Utils/CameraStore.ts +0 -72
  65. package/src/sdk.ts +0 -39
  66. package/src/viewManager.ts +0 -177
@@ -0,0 +1,243 @@
1
+ import type { AkkoObjectUpdatedProperty } from "white-web-sdk";
2
+ import { get, has, isObject } from "lodash";
3
+ import { SideEffectManager } from "side-effect-manager";
4
+ import type { AppContext } from "../../AppContext";
5
+ import { safeListenPropsUpdated } from "../../Utils/Reactive";
6
+ import { isRef, makeRef, plainObjectKeys } from "./utils";
7
+ import type { Diff, MaybeRefValue, RefValue, StorageStateChangedEvent } from "./typings";
8
+ import { StorageEvent } from "./StorageEvent";
9
+
10
+ export * from './typings';
11
+
12
+ const STORAGE_NS = "_WM-STORAGE_";
13
+
14
+ export class Storage<TState = any> implements Storage<TState> {
15
+ readonly id: string;
16
+
17
+ private readonly _context: AppContext<{ [STORAGE_NS]: TState }>;
18
+ private readonly _sideEffect = new SideEffectManager();
19
+ private _state: TState;
20
+ private _destroyed = false;
21
+
22
+ private _refMap = new WeakMap<any, RefValue>();
23
+
24
+ /**
25
+ * `setState` alters local state immediately before sending to server. This will cache the old value for onStateChanged diffing.
26
+ */
27
+ private _lastValue = new Map<string | number | symbol, TState[Extract<keyof TState, string>]>();
28
+
29
+ constructor(context: AppContext<any>, id: string, defaultState?: TState) {
30
+ if (id == null) {
31
+ throw new Error("Cannot create Storage with empty id.");
32
+ }
33
+
34
+ if (defaultState && !isObject(defaultState)) {
35
+ throw new Error(`Default state for Storage ${id} is not an object.`);
36
+ }
37
+
38
+ this._context = context;
39
+ this.id = id;
40
+
41
+ const attrs = context.getAttributes();
42
+ this._state = {} as TState;
43
+ const rawState = get<TState>(attrs, [STORAGE_NS, id], this._state);
44
+
45
+ if (this._context.getIsWritable()) {
46
+ if (!isObject(rawState) || rawState === this._state) {
47
+ if (!attrs[STORAGE_NS]) {
48
+ this._context.updateAttributes([STORAGE_NS], {});
49
+ }
50
+ this._context.updateAttributes([STORAGE_NS, this.id], this._state);
51
+ if (defaultState) {
52
+ this.setState(defaultState);
53
+ }
54
+ } else {
55
+ // strip mobx
56
+ plainObjectKeys(rawState).forEach(key => {
57
+ try {
58
+ const rawValue = isObject(rawState[key]) ? JSON.parse(JSON.stringify(rawState[key])) : rawState[key];
59
+ if (isRef<TState[Extract<keyof TState, string>]>(rawValue)) {
60
+ this._state[key] = rawValue.v;
61
+ if (isObject(rawValue.v)) {
62
+ this._refMap.set(rawValue.v, rawValue);
63
+ }
64
+ } else {
65
+ this._state[key] = rawValue;
66
+ }
67
+ } catch (e) {
68
+ console.error(e);
69
+ }
70
+ });
71
+ }
72
+ }
73
+
74
+ this._sideEffect.addDisposer(
75
+ safeListenPropsUpdated(
76
+ () => get(context.getAttributes(), [STORAGE_NS, this.id]),
77
+ this._updateProperties.bind(this),
78
+ this.destroy.bind(this)
79
+ )
80
+ );
81
+ }
82
+
83
+ get state(): Readonly<TState> {
84
+ if (this._destroyed) {
85
+ console.warn(`Accessing state on destroyed Storage "${this.id}"`)
86
+ }
87
+ return this._state;
88
+ }
89
+
90
+ readonly onStateChanged = new StorageEvent<StorageStateChangedEvent<TState>>();
91
+
92
+ ensureState(state: Partial<TState>): void {
93
+ return this.setState(
94
+ plainObjectKeys(state).reduce((payload, key) => {
95
+ if (!has(this._state, key)) {
96
+ payload[key] = state[key];
97
+ }
98
+ return payload;
99
+ }, {} as Partial<TState>)
100
+ );
101
+ }
102
+
103
+ setState(state: Partial<TState>): void {
104
+ if (this._destroyed) {
105
+ console.error(new Error(`Cannot call setState on destroyed Storage "${this.id}".`));
106
+ return;
107
+ }
108
+
109
+ if (!this._context.getIsWritable()) {
110
+ console.error(new Error(`Cannot setState on Storage "${this.id}" without writable access`), state);
111
+ return;
112
+ }
113
+
114
+ const keys = plainObjectKeys(state);
115
+ if (keys.length > 0) {
116
+ keys.forEach(key => {
117
+ const value = state[key];
118
+ if (value === this._state[key]) {
119
+ return;
120
+ }
121
+
122
+ if (value === void 0) {
123
+ this._lastValue.set(key, this._state[key]);
124
+ delete this._state[key];
125
+ this._context.updateAttributes([STORAGE_NS, this.id, key], value);
126
+ } else {
127
+ this._lastValue.set(key, this._state[key]);
128
+ this._state[key] = value as TState[Extract<keyof TState, string>];
129
+
130
+ let payload: MaybeRefValue<typeof value> = value;
131
+ if (isObject(value)) {
132
+ let refValue = this._refMap.get(value);
133
+ if (!refValue) {
134
+ refValue = makeRef(value);
135
+ this._refMap.set(value, refValue);
136
+ }
137
+ payload = refValue;
138
+ }
139
+
140
+ this._context.updateAttributes([STORAGE_NS, this.id, key], payload);
141
+ }
142
+ });
143
+ }
144
+ }
145
+
146
+ emptyStore(): void {
147
+ if (this._destroyed) {
148
+ console.error(new Error(`Cannot empty destroyed Storage "${this.id}".`));
149
+ return;
150
+ }
151
+
152
+ if (!this._context.getIsWritable()) {
153
+ console.error(new Error(`Cannot empty Storage "${this.id}" without writable access.`));
154
+ return;
155
+ }
156
+
157
+ this._context.updateAttributes([STORAGE_NS, this.id], {});
158
+ }
159
+
160
+ deleteStore(): void {
161
+ if (!this._context.getIsWritable()) {
162
+ console.error(new Error(`Cannot delete Storage "${this.id}" without writable access.`));
163
+ return;
164
+ }
165
+
166
+ this.destroy();
167
+
168
+ this._context.updateAttributes([STORAGE_NS, this.id], void 0);
169
+ }
170
+
171
+ get destroyed(): boolean {
172
+ return this._destroyed;
173
+ }
174
+
175
+ destroy() {
176
+ this._destroyed = true;
177
+ this._sideEffect.flushAll();
178
+ }
179
+
180
+ private _updateProperties(actions: ReadonlyArray<AkkoObjectUpdatedProperty<TState, string>>): void {
181
+ if (this._destroyed) {
182
+ console.error(new Error(`Cannot call _updateProperties on destroyed Storage "${this.id}".`));
183
+ return;
184
+ }
185
+
186
+ if (actions.length > 0) {
187
+ const diffs: Diff<TState> = {};
188
+
189
+ for (let i = 0; i < actions.length; i++) {
190
+ try {
191
+ const action = actions[i]
192
+ const key = action.key as Extract<keyof TState, string>;
193
+ const value = isObject(action.value) ? JSON.parse(JSON.stringify(action.value)) : action.value;
194
+ let oldValue: TState[Extract<keyof TState, string>] | undefined;
195
+ if (this._lastValue.has(key)) {
196
+ oldValue = this._lastValue.get(key);
197
+ this._lastValue.delete(key);
198
+ }
199
+
200
+ switch (action.kind) {
201
+ case 2: {
202
+ // Removed
203
+ if (has(this._state, key)) {
204
+ oldValue = this._state[key];
205
+ delete this._state[key];
206
+ }
207
+ diffs[key] = { oldValue };
208
+ break;
209
+ }
210
+ default: {
211
+ let newValue = value;
212
+
213
+ if (isRef<TState[Extract<keyof TState, string>]>(value)) {
214
+ const { k, v } = value;
215
+ const curValue = this._state[key];
216
+ if (isObject(curValue) && this._refMap.get(curValue)?.k === k) {
217
+ newValue = curValue;
218
+ } else {
219
+ newValue = v;
220
+ if (isObject(v)) {
221
+ this._refMap.set(v, value);
222
+ }
223
+ }
224
+ }
225
+
226
+ if (newValue !== this._state[key]) {
227
+ oldValue = this._state[key];
228
+ this._state[key] = newValue;
229
+ }
230
+
231
+ diffs[key] = { newValue, oldValue };
232
+ break;
233
+ }
234
+ }
235
+ } catch (e) {
236
+ console.error(e)
237
+ }
238
+ }
239
+
240
+ this.onStateChanged.dispatch(diffs);
241
+ }
242
+ }
243
+ }
@@ -0,0 +1,21 @@
1
+ import type { StorageEventListener } from "./StorageEvent";
2
+
3
+ export type RefValue<TValue = any> = { k: string; v: TValue; __isRef: true };
4
+
5
+ export type ExtractRawValue<TValue> = TValue extends RefValue<infer TRefValue> ? TRefValue : TValue;
6
+
7
+ export type AutoRefValue<TValue> = RefValue<ExtractRawValue<TValue>>;
8
+
9
+ export type MaybeRefValue<TValue> = TValue | AutoRefValue<TValue>;
10
+
11
+ export type DiffOne<T> = { oldValue?: T; newValue?: T };
12
+
13
+ export type Diff<T> = { [K in keyof T]?: DiffOne<T[K]> };
14
+
15
+ export type StorageOnSetStatePayload<TState = unknown> = {
16
+ [K in keyof TState]?: MaybeRefValue<TState[K]>;
17
+ };
18
+
19
+ export type StorageStateChangedEvent<TState = any> = Diff<TState>
20
+
21
+ export type StorageStateChangedListener<TState = any> = StorageEventListener<StorageStateChangedEvent<TState>>
@@ -0,0 +1,17 @@
1
+ import { has } from "lodash";
2
+ import { genUID } from "side-effect-manager";
3
+ import type { AutoRefValue, ExtractRawValue, RefValue } from "./typings";
4
+
5
+ export const plainObjectKeys = Object.keys as <T>(o: T) => Array<Extract<keyof T, string>>;
6
+
7
+ export function isRef<TValue = unknown>(e: unknown): e is RefValue<TValue> {
8
+ return Boolean(has(e, '__isRef'));
9
+ }
10
+
11
+ export function makeRef<TValue>(v: TValue): RefValue<TValue> {
12
+ return { k: genUID(), v, __isRef: true };
13
+ }
14
+
15
+ export function makeAutoRef<TValue>(v: TValue): AutoRefValue<TValue> {
16
+ return isRef<ExtractRawValue<TValue>>(v) ? v : makeRef(v as ExtractRawValue<TValue>);
17
+ }
package/src/AppContext.ts CHANGED
@@ -15,6 +15,7 @@ import type { BoxManager } from "./BoxManager";
15
15
  import type { AppEmitterEvent } from "./index";
16
16
  import type { AppManager } from "./AppManager";
17
17
  import type { AppProxy } from "./AppProxy";
18
+ import { Storage } from './App/Storage';
18
19
 
19
20
  export class AppContext<TAttrs extends Record<string, any>, AppOptions = any> {
20
21
  public readonly emitter: Emittery<AppEmitterEvent<TAttrs>>;
@@ -103,7 +104,6 @@ export class AppContext<TAttrs extends Record<string, any>, AppOptions = any> {
103
104
  public async setScenePath(scenePath: string): Promise<void> {
104
105
  if (!this.appProxy.box) return;
105
106
  this.appProxy.setFullPath(scenePath);
106
- this.appProxy.context.switchAppToWriter(this.appId);
107
107
  }
108
108
 
109
109
  public mountView(dom: HTMLDivElement): void {
@@ -120,4 +120,12 @@ export class AppContext<TAttrs extends Record<string, any>, AppOptions = any> {
120
120
  public getAppOptions(): AppOptions | undefined {
121
121
  return typeof this.appOptions === 'function' ? (this.appOptions as () => AppOptions)() : this.appOptions
122
122
  }
123
+
124
+ public createStorage<TState>(storeId: string, defaultState?: TState): Storage<TState> {
125
+ const storage = new Storage(this, storeId, defaultState);
126
+ this.emitter.on("destroy", () => {
127
+ storage.destroy();
128
+ });
129
+ return storage;
130
+ }
123
131
  }
@@ -34,10 +34,6 @@ export class AppListeners {
34
34
  this.appResizeHandler(data.payload);
35
35
  break;
36
36
  }
37
- case Events.SwitchViewsToFreedom: {
38
- this.switchViewsToFreedomHandler();
39
- break;
40
- }
41
37
  case Events.AppBoxStateChange: {
42
38
  this.boxStateChangeHandler(data.payload);
43
39
  break;
@@ -65,10 +61,6 @@ export class AppListeners {
65
61
  this.manager.room?.refreshViewSize();
66
62
  };
67
63
 
68
- private switchViewsToFreedomHandler = () => {
69
- this.manager.viewManager.freedomAllViews();
70
- };
71
-
72
64
  private boxStateChangeHandler = (state: TeleBoxState) => {
73
65
  callbacks.emit("boxStateChange", state);
74
66
  }
package/src/AppManager.ts CHANGED
@@ -2,17 +2,15 @@ import pRetry from "p-retry";
2
2
  import { AppAttributes, AppStatus, Events, MagixEventName } from "./constants";
3
3
  import { AppListeners } from "./AppListener";
4
4
  import { AppProxy } from "./AppProxy";
5
- import { autorun, isPlayer, isRoom, ScenePathType, ViewVisionMode } from "white-web-sdk";
6
- import { callbacks, emitter, WindowManager } from "./index";
7
- import { CameraStore } from "./Utils/CameraStore";
8
- import { genAppId, makeValidScenePath, setScenePath } from "./Utils/Common";
5
+ import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
6
+ import { callbacks, emitter, WindowManager, reconnectRefresher } from "./index";
7
+ import { genAppId, makeValidScenePath, setScenePath, setViewFocusScenePath } from "./Utils/Common";
9
8
  import { log } from "./Utils/log";
10
- import { MainViewProxy } from "./MainView";
9
+ import { MainViewProxy } from "./View/MainView";
11
10
  import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
12
- import { reconnectRefresher } from "./ReconnectRefresher";
13
11
  import { sortBy } from "lodash";
14
12
  import { store } from "./AttributesDelegate";
15
- import { ViewManager } from "./ViewManager";
13
+ import { ViewManager } from "./View/ViewManager";
16
14
  import type { ReconnectRefresher } from "./ReconnectRefresher";
17
15
  import type { BoxManager } from "./BoxManager";
18
16
  import type { Displayer, DisplayerState, Room } from "white-web-sdk";
@@ -20,7 +18,6 @@ import type { AddAppParams, BaseInsertParams, TeleBoxRect, EmitterEvent } from "
20
18
 
21
19
  export class AppManager {
22
20
  public displayer: Displayer;
23
- public cameraStore: CameraStore;
24
21
  public viewManager: ViewManager;
25
22
  public appProxies: Map<string, AppProxy> = new Map();
26
23
  public appStatus: Map<string, AppStatus> = new Map();
@@ -39,9 +36,8 @@ export class AppManager {
39
36
  safeSetAttributes: attributes => this.safeSetAttributes(attributes),
40
37
  safeUpdateAttributes: (keys, val) => this.safeUpdateAttributes(keys, val),
41
38
  });
42
- this.cameraStore = new CameraStore();
43
39
  this.mainViewProxy = new MainViewProxy(this);
44
- this.viewManager = new ViewManager(this);
40
+ this.viewManager = new ViewManager(this.displayer);
45
41
  this.appListeners = new AppListeners(this);
46
42
  this.displayer.callbacks.on(this.eventName, this.displayerStateListener);
47
43
  this.appListeners.addListeners();
@@ -189,15 +185,18 @@ export class AppManager {
189
185
  mainView.disableCameraTransform = disableCameraTransform;
190
186
  mainView.divElement = divElement;
191
187
  if (!mainView.focusScenePath) {
192
- this.store.setMainViewFocusPath(mainView);
188
+ this.setMainViewFocusPath();
193
189
  }
194
- if (this.store.focus === undefined && mainView.mode !== ViewVisionMode.Writable) {
195
- this.viewManager.switchMainViewToWriter();
196
- }
197
- this.mainViewProxy.addMainViewListener();
198
190
  emitter.emit("mainViewMounted");
199
191
  }
200
192
 
193
+ public setMainViewFocusPath() {
194
+ const scenePath = this.store.getMainViewScenePath();
195
+ if (scenePath) {
196
+ setViewFocusScenePath(this.mainView, scenePath);
197
+ }
198
+ }
199
+
201
200
  public async addApp(params: AddAppParams, isDynamicPPT: boolean): Promise<string | undefined> {
202
201
  log("addApp", params);
203
202
  const { appId, needFocus } = await this.beforeAddApp(params, isDynamicPPT);
@@ -283,7 +282,7 @@ export class AppManager {
283
282
  emitter.emit("observerIdChange", this.displayer.observerId);
284
283
  };
285
284
 
286
- private displayerWritableListener = (isReadonly: boolean) => {
285
+ public displayerWritableListener = (isReadonly: boolean) => {
287
286
  const isWritable = !isReadonly;
288
287
  const isManualWritable =
289
288
  this.windowManger.readonly === undefined || this.windowManger.readonly === false;
@@ -296,9 +295,6 @@ export class AppManager {
296
295
  appProxy.emitAppIsWritableChange();
297
296
  });
298
297
  if (isWritable === true) {
299
- if (!this.store.focus) {
300
- this.mainViewProxy.switchViewModeToWriter();
301
- }
302
298
  this.mainView.disableCameraTransform = false;
303
299
  } else {
304
300
  this.mainView.disableCameraTransform = true;
@@ -348,15 +344,16 @@ export class AppManager {
348
344
  await this._setMainViewScenePath(scenePath);
349
345
  } else if (scenePathType === ScenePathType.Dir) {
350
346
  const validScenePath = makeValidScenePath(this.displayer, scenePath);
351
- await this._setMainViewScenePath(validScenePath);
347
+ if (validScenePath) {
348
+ await this._setMainViewScenePath(validScenePath);
349
+ }
352
350
  }
353
351
  }
354
352
  }
355
353
 
356
354
  private async _setMainViewScenePath(scenePath: string) {
357
355
  this.safeSetAttributes({ _mainScenePath: scenePath });
358
- await this.viewManager.switchMainViewToWriter();
359
- setScenePath(this.room, scenePath);
356
+ this.setMainViewFocusPath();
360
357
  this.store.setMainViewFocusPath(this.mainView);
361
358
  this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath: scenePath });
362
359
  }
@@ -364,12 +361,20 @@ export class AppManager {
364
361
  public async setMainViewSceneIndex(index: number) {
365
362
  if (this.room) {
366
363
  this.safeSetAttributes({ _mainSceneIndex: index });
367
- await this.viewManager.switchMainViewToWriter();
368
- this.room.setSceneIndex(index);
369
- const nextScenePath = this.room.state.sceneState.scenePath;
370
- this.store.setMainViewScenePath(nextScenePath);
371
- this.store.setMainViewFocusPath(this.mainView);
372
- this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath });
364
+ const mainViewScenePath = this.store.getMainViewScenePath() as string;
365
+ if (mainViewScenePath) {
366
+ const sceneList = mainViewScenePath.split("/");
367
+ sceneList.pop();
368
+ let sceneDir = sceneList.join("/");
369
+ if (sceneDir === "") {
370
+ sceneDir = "/";
371
+ }
372
+ const scenePath = makeValidScenePath(this.displayer, sceneDir, index);
373
+ if (scenePath) {
374
+ this.store.setMainViewScenePath(scenePath);
375
+ this.setMainViewFocusPath();
376
+ }
377
+ }
373
378
  }
374
379
  }
375
380
 
package/src/AppProxy.ts CHANGED
@@ -2,16 +2,15 @@ import Emittery from "emittery";
2
2
  import { AppAttributes, AppEvents, Events } from "./constants";
3
3
  import { AppContext } from "./AppContext";
4
4
  import { appRegister } from "./Register";
5
- import { autorun, ViewVisionMode } from "white-web-sdk";
6
- import { callbacks, emitter } from "./index";
5
+ import { autorun } from "white-web-sdk";
6
+ import { emitter } from "./index";
7
7
  import { Fields } from "./AttributesDelegate";
8
8
  import { get } from "lodash";
9
9
  import { log } from "./Utils/log";
10
10
  import {
11
- notifyMainViewModeChange,
12
11
  setScenePath,
13
12
  setViewFocusScenePath,
14
- setViewMode,
13
+ getScenePath
15
14
  } from "./Utils/Common";
16
15
  import type {
17
16
  AppEmitterEvent,
@@ -37,7 +36,6 @@ export class AppProxy extends Base {
37
36
  private boxManager = this.manager.boxManager;
38
37
  private appProxies = this.manager.appProxies;
39
38
  private viewManager = this.manager.viewManager;
40
- private cameraStore = this.manager.cameraStore;
41
39
  private kind: string;
42
40
  public isAddApp: boolean;
43
41
  private status: "normal" | "destroyed" = "normal";
@@ -98,17 +96,25 @@ export class AppProxy extends Base {
98
96
 
99
97
  public getFullScenePath(): string | undefined {
100
98
  if (this.scenePath) {
101
- return get(this.appAttributes, [Fields.FullPath], this.scenePath);
99
+ return get(this.appAttributes, [Fields.FullPath], this.getFullScenePathFromScenes());
102
100
  }
103
101
  }
104
102
 
103
+ private getFullScenePathFromScenes() {
104
+ const sceneIndex = get(this.appAttributes, ["state", "SceneIndex"], 0);
105
+ const fullPath = getScenePath(this.manager.room, this.scenePath, sceneIndex);
106
+ if (fullPath) {
107
+ this.setFullPath(fullPath);
108
+ }
109
+ return fullPath;
110
+ }
111
+
105
112
  public setFullPath(path: string) {
106
113
  this.manager.safeUpdateAttributes(["apps", this.id, Fields.FullPath], path);
107
114
  }
108
115
 
109
116
  public async baseInsertApp(
110
117
  skipUpdate = false,
111
- focus?: boolean
112
118
  ): Promise<{ appId: string; app: NetlessApp }> {
113
119
  const params = this.params;
114
120
  if (!params.kind) {
@@ -122,9 +128,6 @@ export class AppProxy extends Base {
122
128
  throw new Error(`[WindowManager]: app load failed ${params.kind} ${params.src}`);
123
129
  }
124
130
  this.context.updateManagerRect();
125
- if (focus) {
126
- this.focusApp();
127
- }
128
131
  return {
129
132
  appId: this.id,
130
133
  app: appImpl,
@@ -133,7 +136,6 @@ export class AppProxy extends Base {
133
136
 
134
137
  private focusApp() {
135
138
  this.focusBox();
136
- this.context.switchAppToWriter(this.id);
137
139
  this.store.setMainViewFocusPath(this.manager.mainView);
138
140
  }
139
141
 
@@ -205,9 +207,6 @@ export class AppProxy extends Base {
205
207
 
206
208
  private afterSetupApp(boxInitState: AppInitState | undefined): void {
207
209
  if (boxInitState) {
208
- if (boxInitState.focus && this.scenePath) {
209
- this.context.switchAppToWriter(this.id);
210
- }
211
210
  if (!boxInitState?.x || !boxInitState.y) {
212
211
  this.boxManager?.setBoxInitState(this.id);
213
212
  }
@@ -226,29 +225,10 @@ export class AppProxy extends Base {
226
225
  await this.destroy(true, false, true);
227
226
  const params = this.params;
228
227
  const appProxy = new AppProxy(params, this.manager, this.id, this.isAddApp);
229
- await appProxy.baseInsertApp(true, this.store.focus === this.id);
228
+ await appProxy.baseInsertApp(true);
230
229
  this.boxManager?.updateBoxState(currentAppState);
231
230
  }
232
231
 
233
- public switchToWritable() {
234
- appRegister.notifyApp(this.kind, "focus", { appId: this.id });
235
- this.cameraStore.switchView(this.id, this.view, () => {
236
- if (this.view) {
237
- if (this.view.mode === ViewVisionMode.Writable) return;
238
- try {
239
- if (this.manager.mainView.mode === ViewVisionMode.Writable) {
240
- this.store.setMainViewFocusPath(this.manager.mainView);
241
- notifyMainViewModeChange(callbacks, ViewVisionMode.Freedom);
242
- setViewMode(this.manager.mainView, ViewVisionMode.Freedom);
243
- }
244
- setViewMode(this.view, ViewVisionMode.Writable);
245
- } catch (error) {
246
- log("switch view failed", error);
247
- }
248
- }
249
- });
250
- }
251
-
252
232
  public getAppInitState = (id: string) => {
253
233
  const attrs = this.store.getAppState(id);
254
234
  if (!attrs) return;
@@ -364,7 +344,6 @@ export class AppProxy extends Base {
364
344
 
365
345
  private async createView(): Promise<View> {
366
346
  const view = await this.viewManager.createView(this.id);
367
- this.cameraStore.register(this.id, view);
368
347
  this.setViewFocusScenePath();
369
348
  return view;
370
349
  }
@@ -388,7 +367,6 @@ export class AppProxy extends Base {
388
367
  this.store.cleanAppAttributes(this.id);
389
368
  }
390
369
  this.appProxies.delete(this.id);
391
- this.cameraStore.unregister(this.id, this.view);
392
370
 
393
371
  this.viewManager.destroyView(this.id);
394
372
  this.manager.appStatus.delete(this.id);
@@ -33,10 +33,6 @@ export class Context {
33
33
  public blurFocusBox() {
34
34
  this.manager.boxManager?.blurAllBox();
35
35
  }
36
-
37
- public switchAppToWriter(id: string) {
38
- this.manager.viewManager.switchAppToWriter(id);
39
- }
40
36
  }
41
37
 
42
38
  let context: Context;
package/src/BoxManager.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AppAttributes, DEFAULT_COLLECTOR_STYLE, Events, MIN_HEIGHT, MIN_WIDTH } from "./constants";
1
+ import { AppAttributes, Events, MIN_HEIGHT, MIN_WIDTH } from "./constants";
2
2
  import { debounce, maxBy } from "lodash";
3
3
  import {
4
4
  TELE_BOX_MANAGER_EVENT,
@@ -6,7 +6,7 @@ import {
6
6
  TeleBoxCollector,
7
7
  TeleBoxManager,
8
8
  } from "@netless/telebox-insider";
9
- import { WindowManager } from "./index";
9
+ import { emitter, WindowManager } from "./index";
10
10
  import type { AddAppOptions, AppInitState, EmitterType, CallbacksType } from "./index";
11
11
  import type {
12
12
  TeleBoxManagerUpdateConfig,
@@ -145,6 +145,11 @@ export class BoxManager {
145
145
  this.teleBoxManager.events.on("z_index", box => {
146
146
  this.context.updateAppState(box.id, AppAttributes.ZIndex, box.zIndex);
147
147
  });
148
+ emitter.on("playgroundSizeChange", this.playgroundSizeChangeListener);
149
+ }
150
+
151
+ private playgroundSizeChangeListener = () => {
152
+ this.updateManagerRect();
148
153
  }
149
154
 
150
155
  private get mainView() {
@@ -251,12 +256,8 @@ export class BoxManager {
251
256
  }
252
257
 
253
258
  public setCollectorContainer(container: HTMLElement) {
254
- const styles = {
255
- ...DEFAULT_COLLECTOR_STYLE,
256
- ...this.createTeleBoxManagerConfig?.collectorStyles,
257
- };
258
259
  const collector = new TeleBoxCollector({
259
- styles
260
+ styles: this.createTeleBoxManagerConfig?.collectorStyles,
260
261
  }).mount(container);
261
262
  this.teleBoxManager.setCollector(collector);
262
263
  }
@@ -391,6 +392,7 @@ export class BoxManager {
391
392
  }
392
393
 
393
394
  public destroy() {
395
+ emitter.off("playgroundSizeChange", this.playgroundSizeChangeListener);
394
396
  this.teleBoxManager.destroy();
395
397
  }
396
398
  }
@@ -0,0 +1,24 @@
1
+ import AppDocsViewer from "@netless/app-docs-viewer";
2
+ import AppMediaPlayer, { setOptions } from "@netless/app-media-player";
3
+ import { WindowManager } from "./index";
4
+ import "@netless/app-docs-viewer/dist/style.css";
5
+
6
+ export const setupBuiltin = () => {
7
+ if (WindowManager.debug) {
8
+ setOptions({ verbose: true });
9
+ }
10
+
11
+ WindowManager.register({
12
+ kind: AppDocsViewer.kind,
13
+ src: AppDocsViewer,
14
+ });
15
+ WindowManager.register({
16
+ kind: AppMediaPlayer.kind,
17
+ src: AppMediaPlayer,
18
+ });
19
+ };
20
+
21
+ export const BuiltinApps = {
22
+ DocsViewer: AppDocsViewer.kind as string,
23
+ MediaPlayer: AppMediaPlayer.kind as string,
24
+ };