@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.
- package/dist/index.es.js +1 -1
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/src/App/Storage/StorageEvent.d.ts +8 -0
- package/dist/src/App/Storage/index.d.ts +26 -0
- package/dist/src/App/Storage/typings.d.ts +21 -0
- package/dist/src/App/Storage/utils.d.ts +5 -0
- package/dist/{AppContext.d.ts → src/AppContext.d.ts} +2 -0
- package/dist/{AppListener.d.ts → src/AppListener.d.ts} +0 -1
- package/dist/{AppManager.d.ts → src/AppManager.d.ts} +4 -5
- package/dist/{AppProxy.d.ts → src/AppProxy.d.ts} +2 -3
- package/dist/{AttributesDelegate.d.ts → src/AttributesDelegate.d.ts} +0 -0
- package/dist/{Base → src/Base}/Context.d.ts +0 -1
- package/dist/{Base → src/Base}/index.d.ts +0 -0
- package/dist/{BoxManager.d.ts → src/BoxManager.d.ts} +2 -1
- package/dist/src/BuiltinApps.d.ts +6 -0
- package/dist/src/ContainerResizeObserver.d.ts +10 -0
- package/dist/{Cursor → src/Cursor}/Cursor.d.ts +0 -0
- package/dist/{Cursor → src/Cursor}/icons.d.ts +0 -0
- package/dist/{Cursor → src/Cursor}/index.d.ts +0 -0
- package/dist/src/Helper.d.ts +6 -0
- package/dist/{ReconnectRefresher.d.ts → src/ReconnectRefresher.d.ts} +0 -1
- package/dist/{Register → src/Register}/index.d.ts +0 -0
- package/dist/{Register → src/Register}/loader.d.ts +0 -0
- package/dist/{Register → src/Register}/storage.d.ts +0 -0
- package/dist/{Utils → src/Utils}/Common.d.ts +3 -1
- package/dist/{Utils → src/Utils}/Reactive.d.ts +1 -1
- package/dist/{Utils → src/Utils}/RoomHacker.d.ts +0 -0
- package/dist/{Utils → src/Utils}/error.d.ts +0 -0
- package/dist/{Utils → src/Utils}/log.d.ts +0 -0
- package/dist/{MainView.d.ts → src/View/MainView.d.ts} +2 -4
- package/dist/src/View/ViewManager.d.ts +13 -0
- package/dist/{constants.d.ts → src/constants.d.ts} +0 -5
- package/dist/{index.d.ts → src/index.d.ts} +4 -8
- package/dist/{typings.d.ts → src/typings.d.ts} +1 -0
- package/dist/style.css +1 -1
- package/package.json +3 -3
- package/src/App/Storage/StorageEvent.ts +21 -0
- package/src/App/Storage/index.ts +243 -0
- package/src/App/Storage/typings.ts +21 -0
- package/src/App/Storage/utils.ts +17 -0
- package/src/AppContext.ts +9 -1
- package/src/AppListener.ts +0 -8
- package/src/AppManager.ts +33 -28
- package/src/AppProxy.ts +14 -36
- package/src/Base/Context.ts +0 -4
- package/src/BoxManager.ts +9 -7
- package/src/BuiltinApps.ts +24 -0
- package/src/ContainerResizeObserver.ts +62 -0
- package/src/Helper.ts +30 -0
- package/src/ReconnectRefresher.ts +0 -5
- package/src/Utils/Common.ts +35 -13
- package/src/Utils/Reactive.ts +9 -3
- package/src/{MainView.ts → View/MainView.ts} +7 -25
- package/src/View/ViewManager.ts +53 -0
- package/src/constants.ts +0 -2
- package/src/index.ts +20 -69
- package/src/style.css +6 -0
- package/src/typings.ts +1 -0
- package/dist/Utils/CameraStore.d.ts +0 -15
- package/dist/ViewManager.d.ts +0 -29
- package/dist/sdk.d.ts +0 -14
- package/src/Utils/CameraStore.ts +0 -72
- package/src/sdk.ts +0 -39
- 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
|
}
|
package/src/AppListener.ts
CHANGED
@@ -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
|
6
|
-
import { callbacks, emitter, WindowManager } from "./index";
|
7
|
-
import {
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
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
|
6
|
-
import {
|
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
|
-
|
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.
|
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
|
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);
|
package/src/Base/Context.ts
CHANGED
package/src/BoxManager.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { AppAttributes,
|
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
|
+
};
|