@netless/window-manager 0.4.0-canary.9 → 0.4.2
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/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/window-manager.iml +12 -0
- package/.vscode/settings.json +1 -0
- package/CHANGELOG.md +43 -2
- package/README.md +3 -0
- package/dist/App/MagixEvent/index.d.ts +29 -0
- package/dist/App/Storage/index.d.ts +19 -6
- package/dist/App/Storage/typings.d.ts +1 -0
- package/dist/AppContext.d.ts +39 -17
- package/dist/AppListener.d.ts +2 -0
- package/dist/AppManager.d.ts +22 -8
- package/dist/AppProxy.d.ts +5 -5
- package/dist/AttributesDelegate.d.ts +2 -2
- package/dist/BoxManager.d.ts +6 -4
- package/dist/BuiltinApps.d.ts +0 -1
- package/dist/Cursor/Cursor.d.ts +10 -12
- package/dist/Cursor/index.d.ts +6 -16
- package/dist/Helper.d.ts +1 -0
- package/dist/Register/index.d.ts +5 -0
- package/dist/Register/storage.d.ts +5 -1
- package/dist/Utils/AppCreateQueue.d.ts +11 -0
- package/dist/Utils/Common.d.ts +4 -1
- package/dist/Utils/RoomHacker.d.ts +3 -3
- package/dist/View/MainView.d.ts +4 -3
- package/dist/constants.d.ts +5 -2
- package/dist/index.d.ts +32 -6
- package/dist/index.es.js +41 -1
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +41 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/typings.d.ts +2 -2
- package/docs/advanced.md +53 -0
- package/docs/api.md +79 -6
- package/docs/concept.md +9 -0
- package/docs/replay.md +40 -0
- package/package.json +8 -9
- package/src/App/MagixEvent/index.ts +68 -0
- package/src/App/Storage/index.ts +89 -43
- package/src/App/Storage/typings.ts +4 -2
- package/src/AppContext.ts +61 -24
- package/src/AppListener.ts +27 -8
- package/src/AppManager.ts +231 -70
- package/src/AppProxy.ts +40 -29
- package/src/AttributesDelegate.ts +2 -2
- package/src/BoxManager.ts +33 -19
- package/src/BuiltinApps.ts +0 -1
- package/src/ContainerResizeObserver.ts +3 -3
- package/src/Cursor/Cursor.svelte +25 -21
- package/src/Cursor/Cursor.ts +25 -38
- package/src/Cursor/icons.ts +2 -0
- package/src/Cursor/index.ts +45 -139
- package/src/Helper.ts +12 -1
- package/src/Register/index.ts +32 -17
- package/src/Register/loader.ts +28 -13
- package/src/Register/storage.ts +6 -1
- package/src/Utils/AppCreateQueue.ts +54 -0
- package/src/Utils/Common.ts +35 -2
- package/src/Utils/RoomHacker.ts +33 -18
- package/src/View/MainView.ts +19 -12
- package/src/View/ViewManager.ts +1 -2
- package/src/constants.ts +6 -2
- package/src/image/laser-pointer-cursor.svg +17 -0
- package/src/index.ts +150 -33
- package/src/shim.d.ts +2 -1
- package/src/style.css +6 -1
- package/src/typings.ts +2 -2
- package/vite.config.js +7 -4
- package/dist/Base/Context.d.ts +0 -12
- package/dist/Base/index.d.ts +0 -7
- package/src/Base/Context.ts +0 -45
- package/src/Base/index.ts +0 -10
package/src/AppContext.ts
CHANGED
@@ -6,9 +6,9 @@ import {
|
|
6
6
|
unlistenDisposed,
|
7
7
|
unlistenUpdated,
|
8
8
|
toJS
|
9
|
-
|
9
|
+
} from 'white-web-sdk';
|
10
10
|
import { BoxNotCreatedError } from './Utils/error';
|
11
|
-
import type { Room, SceneDefinition, View } from "white-web-sdk";
|
11
|
+
import type { Room, SceneDefinition, View, EventListener as WhiteEventListener } from "white-web-sdk";
|
12
12
|
import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
13
13
|
import type Emittery from "emittery";
|
14
14
|
import type { BoxManager } from "./BoxManager";
|
@@ -16,9 +16,10 @@ import type { AppEmitterEvent } from "./index";
|
|
16
16
|
import type { AppManager } from "./AppManager";
|
17
17
|
import type { AppProxy } from "./AppProxy";
|
18
18
|
import { Storage } from './App/Storage';
|
19
|
+
import type { MagixEventAddListener, MagixEventDispatcher, MagixEventRemoveListener } from './App/MagixEvent';
|
19
20
|
|
20
|
-
export class AppContext<
|
21
|
-
public readonly emitter: Emittery<AppEmitterEvent<
|
21
|
+
export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOptions = any> {
|
22
|
+
public readonly emitter: Emittery<AppEmitterEvent<TAttributes>>;
|
22
23
|
public readonly mobxUtils = {
|
23
24
|
autorun,
|
24
25
|
reaction,
|
@@ -40,45 +41,45 @@ export class AppContext<TAttrs extends Record<string, any> = any, AppOptions = a
|
|
40
41
|
private boxManager: BoxManager,
|
41
42
|
public appId: string,
|
42
43
|
private appProxy: AppProxy,
|
43
|
-
private appOptions?:
|
44
|
+
private appOptions?: TAppOptions | (() => TAppOptions),
|
44
45
|
) {
|
45
46
|
this.emitter = appProxy.appEmitter;
|
46
47
|
this.isAddApp = appProxy.isAddApp;
|
47
48
|
}
|
48
49
|
|
49
|
-
public getDisplayer() {
|
50
|
+
public getDisplayer = () => {
|
50
51
|
return this.manager.displayer;
|
51
52
|
}
|
52
53
|
|
53
|
-
|
54
|
+
/** @deprecated Use context.storage.state instead. */
|
55
|
+
public getAttributes = (): TAttributes | undefined => {
|
54
56
|
return this.appProxy.attributes;
|
55
57
|
}
|
56
58
|
|
57
|
-
public getScenes(): SceneDefinition[] | undefined {
|
59
|
+
public getScenes = (): SceneDefinition[] | undefined => {
|
58
60
|
const appAttr = this.store.getAppAttributes(this.appId);
|
59
61
|
if (appAttr?.isDynamicPPT) {
|
60
|
-
|
61
|
-
if (appProxy) {
|
62
|
-
return appProxy.scenes;
|
63
|
-
}
|
62
|
+
return this.appProxy.scenes;
|
64
63
|
} else {
|
65
64
|
return appAttr?.options["scenes"];
|
66
65
|
}
|
67
66
|
}
|
68
67
|
|
69
|
-
public getView(): View | undefined {
|
68
|
+
public getView = (): View | undefined => {
|
70
69
|
return this.appProxy.view;
|
71
70
|
}
|
72
71
|
|
73
|
-
public getInitScenePath() {
|
72
|
+
public getInitScenePath = () => {
|
74
73
|
return this.manager.getAppInitPath(this.appId);
|
75
74
|
}
|
76
75
|
|
77
|
-
|
76
|
+
/** Get App writable status. */
|
77
|
+
public getIsWritable = (): boolean => {
|
78
78
|
return this.manager.canOperate;
|
79
79
|
}
|
80
80
|
|
81
|
-
|
81
|
+
/** Get the App Window UI box. */
|
82
|
+
public getBox = (): ReadonlyTeleBox => {
|
82
83
|
const box = this.boxManager.getBox(this.appId);
|
83
84
|
if (box) {
|
84
85
|
return box;
|
@@ -87,26 +88,30 @@ export class AppContext<TAttrs extends Record<string, any> = any, AppOptions = a
|
|
87
88
|
}
|
88
89
|
}
|
89
90
|
|
90
|
-
public getRoom(): Room | undefined {
|
91
|
+
public getRoom = (): Room | undefined => {
|
91
92
|
return this.manager.room;
|
92
93
|
}
|
93
94
|
|
94
|
-
|
95
|
+
/** @deprecated Use context.storage.setState instead. */
|
96
|
+
public setAttributes = (attributes: TAttributes) => {
|
95
97
|
this.manager.safeSetAttributes({ [this.appId]: attributes });
|
96
98
|
}
|
97
99
|
|
98
|
-
|
100
|
+
/** @deprecated Use context.storage.setState instead. */
|
101
|
+
public updateAttributes = (keys: string[], value: any) => {
|
99
102
|
if (this.manager.attributes[this.appId]) {
|
100
103
|
this.manager.safeUpdateAttributes([this.appId, ...keys], value);
|
101
104
|
}
|
102
105
|
}
|
103
106
|
|
104
|
-
public async
|
107
|
+
public setScenePath = async (scenePath: string): Promise<void> => {
|
105
108
|
if (!this.appProxy.box) return;
|
106
109
|
this.appProxy.setFullPath(scenePath);
|
110
|
+
// 兼容 15 版本 SDK 的切页
|
111
|
+
this.getRoom()?.setScenePath(scenePath);
|
107
112
|
}
|
108
113
|
|
109
|
-
public mountView(dom: HTMLDivElement): void {
|
114
|
+
public mountView = (dom: HTMLDivElement): void => {
|
110
115
|
const view = this.getView();
|
111
116
|
if (view) {
|
112
117
|
view.divElement = dom;
|
@@ -117,15 +122,47 @@ export class AppContext<TAttrs extends Record<string, any> = any, AppOptions = a
|
|
117
122
|
}
|
118
123
|
}
|
119
124
|
|
120
|
-
|
121
|
-
|
125
|
+
/** Get the local App options. */
|
126
|
+
public getAppOptions = (): TAppOptions | undefined => {
|
127
|
+
return typeof this.appOptions === 'function' ? (this.appOptions as () => TAppOptions)() : this.appOptions
|
122
128
|
}
|
123
129
|
|
124
|
-
|
130
|
+
private _storage?: Storage<TAttributes>
|
131
|
+
|
132
|
+
/** Main Storage for attributes. */
|
133
|
+
public get storage(): Storage<TAttributes> {
|
134
|
+
if (!this._storage) {
|
135
|
+
this._storage = new Storage(this);
|
136
|
+
}
|
137
|
+
return this._storage;
|
138
|
+
}
|
139
|
+
|
140
|
+
/**
|
141
|
+
* Create separated storages for flexible state management.
|
142
|
+
* @param storeId Namespace for the storage. Storages of the same namespace share the same data.
|
143
|
+
* @param defaultState Default state for initial storage creation.
|
144
|
+
* @returns
|
145
|
+
*/
|
146
|
+
public createStorage = <TState>(storeId: string, defaultState?: TState): Storage<TState> => {
|
125
147
|
const storage = new Storage(this, storeId, defaultState);
|
126
148
|
this.emitter.on("destroy", () => {
|
127
149
|
storage.destroy();
|
128
150
|
});
|
129
151
|
return storage;
|
130
152
|
}
|
153
|
+
|
154
|
+
/** Dispatch events to other clients (and self). */
|
155
|
+
public dispatchMagixEvent: MagixEventDispatcher<TMagixEventPayloads> = (...args) => {
|
156
|
+
// can't dispatch events on replay mode
|
157
|
+
return this.manager.room?.dispatchMagixEvent(...args);
|
158
|
+
}
|
159
|
+
|
160
|
+
/** Listen to events from others clients (and self messages). */
|
161
|
+
public addMagixEventListener: MagixEventAddListener<TMagixEventPayloads> = (event, handler, options) => {
|
162
|
+
this.manager.displayer.addMagixEventListener(event, handler as WhiteEventListener, options);
|
163
|
+
return () => this.manager.displayer.removeMagixEventListener(event, handler as WhiteEventListener);
|
164
|
+
}
|
165
|
+
|
166
|
+
/** Remove a Magix event listener. */
|
167
|
+
public removeMagixEventListener = this.manager.displayer.removeMagixEventListener.bind(this.manager.displayer) as MagixEventRemoveListener<TMagixEventPayloads>
|
131
168
|
}
|
package/src/AppListener.ts
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
import { callbacks } from
|
2
|
-
import { Events, MagixEventName } from
|
3
|
-
import
|
1
|
+
import { callbacks, emitter } from "./index";
|
2
|
+
import { Events, MagixEventName } from "./constants";
|
3
|
+
import { isEqual, omit } from "lodash";
|
4
|
+
import { setViewFocusScenePath } from "./Utils/Common";
|
5
|
+
import type { AnimationMode, Camera, Event } from "white-web-sdk";
|
4
6
|
import type { AppManager } from "./AppManager";
|
5
7
|
import type { TeleBoxState } from "@netless/telebox-insider";
|
6
|
-
import { setViewFocusScenePath } from './Utils/Common';
|
7
|
-
|
8
8
|
export class AppListeners {
|
9
9
|
private displayer = this.manager.displayer;
|
10
10
|
|
@@ -42,10 +42,18 @@ export class AppListeners {
|
|
42
42
|
this.setMainViewScenePathHandler(data.payload);
|
43
43
|
break;
|
44
44
|
}
|
45
|
+
case Events.MoveCamera: {
|
46
|
+
this.moveCameraHandler(data.payload);
|
47
|
+
break;
|
48
|
+
}
|
45
49
|
case Events.MoveCameraToContain: {
|
46
50
|
this.moveCameraToContainHandler(data.payload);
|
47
51
|
break;
|
48
52
|
}
|
53
|
+
case Events.CursorMove: {
|
54
|
+
this.cursorMoveHandler(data.payload);
|
55
|
+
break;
|
56
|
+
}
|
49
57
|
default:
|
50
58
|
break;
|
51
59
|
}
|
@@ -63,14 +71,25 @@ export class AppListeners {
|
|
63
71
|
|
64
72
|
private boxStateChangeHandler = (state: TeleBoxState) => {
|
65
73
|
callbacks.emit("boxStateChange", state);
|
66
|
-
}
|
74
|
+
};
|
67
75
|
|
68
76
|
private setMainViewScenePathHandler = ({ nextScenePath }: { nextScenePath: string }) => {
|
69
77
|
setViewFocusScenePath(this.manager.mainView, nextScenePath);
|
70
78
|
callbacks.emit("mainViewScenePathChange", nextScenePath);
|
71
|
-
}
|
79
|
+
};
|
80
|
+
|
81
|
+
private moveCameraHandler = (
|
82
|
+
payload: Camera & { animationMode?: AnimationMode | undefined }
|
83
|
+
) => {
|
84
|
+
if (isEqual(omit(payload, ["animationMode"]), { ...this.manager.mainView.camera })) return;
|
85
|
+
this.manager.mainView.moveCamera(payload);
|
86
|
+
};
|
72
87
|
|
73
88
|
private moveCameraToContainHandler = (payload: any) => {
|
74
89
|
this.manager.mainView.moveCameraToContain(payload);
|
75
|
-
}
|
90
|
+
};
|
91
|
+
|
92
|
+
private cursorMoveHandler = (payload: any) => {
|
93
|
+
emitter.emit("cursorMove", payload);
|
94
|
+
};
|
76
95
|
}
|
package/src/AppManager.ts
CHANGED
@@ -1,19 +1,27 @@
|
|
1
|
-
import
|
2
|
-
import {
|
1
|
+
import { AppAttributes, AppStatus, Events, MagixEventName, ROOT_DIR } from "./constants";
|
2
|
+
import { AppCreateQueue } from "./Utils/AppCreateQueue";
|
3
3
|
import { AppListeners } from "./AppListener";
|
4
4
|
import { AppProxy } from "./AppProxy";
|
5
|
+
import { appRegister } from "./Register";
|
5
6
|
import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
|
6
|
-
import { callbacks, emitter,
|
7
|
-
import {
|
7
|
+
import { callbacks, emitter, reconnectRefresher, WindowManager } from "./index";
|
8
|
+
import { get, isInteger, orderBy } from "lodash";
|
8
9
|
import { log } from "./Utils/log";
|
9
10
|
import { MainViewProxy } from "./View/MainView";
|
10
11
|
import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
|
11
|
-
import { get, sortBy } from "lodash";
|
12
12
|
import { store } from "./AttributesDelegate";
|
13
13
|
import { ViewManager } from "./View/ViewManager";
|
14
|
+
import {
|
15
|
+
entireScenes,
|
16
|
+
genAppId,
|
17
|
+
makeValidScenePath,
|
18
|
+
parseSceneDir,
|
19
|
+
setScenePath,
|
20
|
+
setViewFocusScenePath,
|
21
|
+
} from "./Utils/Common";
|
14
22
|
import type { ReconnectRefresher } from "./ReconnectRefresher";
|
15
23
|
import type { BoxManager } from "./BoxManager";
|
16
|
-
import type { Displayer, DisplayerState, Room } from "white-web-sdk";
|
24
|
+
import type { Displayer, DisplayerState, Room, ScenesCallbacksNode, View } from "white-web-sdk";
|
17
25
|
import type { AddAppParams, BaseInsertParams, TeleBoxRect, EmitterEvent } from "./index";
|
18
26
|
|
19
27
|
export class AppManager {
|
@@ -25,11 +33,15 @@ export class AppManager {
|
|
25
33
|
public mainViewProxy: MainViewProxy;
|
26
34
|
public refresher?: ReconnectRefresher;
|
27
35
|
public isReplay = this.windowManger.isReplay;
|
36
|
+
public mainViewScenesLength = 0;
|
28
37
|
|
29
38
|
private appListeners: AppListeners;
|
30
39
|
public boxManager?: BoxManager;
|
31
40
|
|
32
41
|
private _prevSceneIndex: number | undefined;
|
42
|
+
private _prevFocused: string | undefined;
|
43
|
+
private callbacksNode: ScenesCallbacksNode | null;
|
44
|
+
private appCreateQueue = new AppCreateQueue();
|
33
45
|
|
34
46
|
constructor(public windowManger: WindowManager) {
|
35
47
|
this.displayer = windowManger.displayer;
|
@@ -59,6 +71,70 @@ export class AppManager {
|
|
59
71
|
this.onAppDelete(this.attributes.apps);
|
60
72
|
});
|
61
73
|
}
|
74
|
+
emitter.on("removeScenes", scenePath => {
|
75
|
+
if (scenePath === ROOT_DIR) {
|
76
|
+
this.setMainViewScenePath(ROOT_DIR);
|
77
|
+
return;
|
78
|
+
}
|
79
|
+
const mainViewScenePath = this.store.getMainViewScenePath();
|
80
|
+
if (this.room && mainViewScenePath) {
|
81
|
+
if (mainViewScenePath === scenePath) {
|
82
|
+
this.setMainViewScenePath(ROOT_DIR);
|
83
|
+
}
|
84
|
+
}
|
85
|
+
});
|
86
|
+
this.callbacksNode = this.displayer.createScenesCallback(ROOT_DIR, {
|
87
|
+
onAddScene: scenesCallback => {
|
88
|
+
this.mainViewScenesLength = scenesCallback.scenes.length;
|
89
|
+
callbacks.emit("mainViewScenesLengthChange", this.mainViewScenesLength);
|
90
|
+
},
|
91
|
+
onRemoveScene: scenesCallback => {
|
92
|
+
this.mainViewScenesLength = scenesCallback.scenes.length;
|
93
|
+
callbacks.emit("mainViewScenesLengthChange", this.mainViewScenesLength);
|
94
|
+
},
|
95
|
+
});
|
96
|
+
if (this.callbacksNode) {
|
97
|
+
this.mainViewScenesLength = this.callbacksNode.scenes.length;
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
private get eventName() {
|
102
|
+
return isRoom(this.displayer) ? "onRoomStateChanged" : "onPlayerStateChanged";
|
103
|
+
}
|
104
|
+
|
105
|
+
public get attributes() {
|
106
|
+
return this.windowManger.attributes;
|
107
|
+
}
|
108
|
+
|
109
|
+
public get canOperate() {
|
110
|
+
return this.windowManger.canOperate;
|
111
|
+
}
|
112
|
+
|
113
|
+
public get room() {
|
114
|
+
return isRoom(this.displayer) ? (this.displayer as Room) : undefined;
|
115
|
+
}
|
116
|
+
|
117
|
+
public get mainView() {
|
118
|
+
return this.mainViewProxy.view;
|
119
|
+
}
|
120
|
+
|
121
|
+
public get focusApp() {
|
122
|
+
if (this.store.focus) {
|
123
|
+
return this.appProxies.get(this.store.focus);
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
public get uid() {
|
128
|
+
return this.room?.uid || "";
|
129
|
+
}
|
130
|
+
|
131
|
+
public getMainViewSceneDir() {
|
132
|
+
const scenePath = this.store.getMainViewScenePath();
|
133
|
+
if (scenePath) {
|
134
|
+
return parseSceneDir(scenePath);
|
135
|
+
} else {
|
136
|
+
throw new Error("[WindowManager]: mainViewSceneDir not found");
|
137
|
+
}
|
62
138
|
}
|
63
139
|
|
64
140
|
private async onCreated() {
|
@@ -106,6 +182,29 @@ export class AppManager {
|
|
106
182
|
}
|
107
183
|
});
|
108
184
|
});
|
185
|
+
this.refresher?.add("focusedChange", () => {
|
186
|
+
return autorun(() => {
|
187
|
+
const focused = get(this.attributes, "focus");
|
188
|
+
if (this._prevFocused !== focused) {
|
189
|
+
callbacks.emit("focusedChange", focused);
|
190
|
+
this.disposePrevFocusViewRedoUndoListeners(this._prevFocused);
|
191
|
+
setTimeout(() => {
|
192
|
+
this.addRedoUndoListeners(focused);
|
193
|
+
}, 0);
|
194
|
+
this._prevFocused = focused;
|
195
|
+
if (focused !== undefined) {
|
196
|
+
this.boxManager?.focusBox({ appId: focused });
|
197
|
+
// 确保 focus 修改的时候, appProxy 已经创建
|
198
|
+
setTimeout(() => {
|
199
|
+
const appProxy = this.appProxies.get(focused);
|
200
|
+
if (appProxy) {
|
201
|
+
appRegister.notifyApp(appProxy.kind, "focus", { appId: focused });
|
202
|
+
}
|
203
|
+
}, 0);
|
204
|
+
}
|
205
|
+
}
|
206
|
+
});
|
207
|
+
});
|
109
208
|
if (!this.attributes.apps || Object.keys(this.attributes.apps).length === 0) {
|
110
209
|
const mainScenePath = this.store.getMainViewScenePath();
|
111
210
|
if (!mainScenePath) return;
|
@@ -116,8 +215,61 @@ export class AppManager {
|
|
116
215
|
}
|
117
216
|
this.displayerWritableListener(!this.room?.isWritable);
|
118
217
|
this.displayer.callbacks.on("onEnableWriteNowChanged", this.displayerWritableListener);
|
218
|
+
this._prevFocused = this.attributes.focus;
|
219
|
+
this.addRedoUndoListeners(this.attributes.focus);
|
119
220
|
}
|
120
221
|
|
222
|
+
private disposePrevFocusViewRedoUndoListeners = (prevFocused: string | undefined) => {
|
223
|
+
if (prevFocused === undefined) {
|
224
|
+
this.mainView.callbacks.off("onCanRedoStepsUpdate", this.onCanRedoStepsUpdate);
|
225
|
+
this.mainView.callbacks.off("onCanUndoStepsUpdate", this.onCanRedoStepsUpdate);
|
226
|
+
} else {
|
227
|
+
const appProxy = this.appProxies.get(prevFocused);
|
228
|
+
if (appProxy) {
|
229
|
+
appProxy.view?.callbacks.off("onCanRedoStepsUpdate", this.onCanRedoStepsUpdate);
|
230
|
+
appProxy.view?.callbacks.off("onCanUndoStepsUpdate", this.onCanUndoStepsUpdate);
|
231
|
+
}
|
232
|
+
}
|
233
|
+
};
|
234
|
+
|
235
|
+
private addRedoUndoListeners = (focused: string | undefined) => {
|
236
|
+
if (focused === undefined) {
|
237
|
+
this.addViewCallbacks(
|
238
|
+
this.mainView,
|
239
|
+
this.onCanRedoStepsUpdate,
|
240
|
+
this.onCanUndoStepsUpdate
|
241
|
+
);
|
242
|
+
} else {
|
243
|
+
const focusApp = this.appProxies.get(focused);
|
244
|
+
if (focusApp && focusApp.view) {
|
245
|
+
this.addViewCallbacks(
|
246
|
+
focusApp.view,
|
247
|
+
this.onCanRedoStepsUpdate,
|
248
|
+
this.onCanUndoStepsUpdate
|
249
|
+
);
|
250
|
+
}
|
251
|
+
}
|
252
|
+
};
|
253
|
+
|
254
|
+
private addViewCallbacks = (
|
255
|
+
view: View,
|
256
|
+
redoListener: (steps: number) => void,
|
257
|
+
undoListener: (steps: number) => void
|
258
|
+
) => {
|
259
|
+
redoListener(view.canRedoSteps);
|
260
|
+
undoListener(view.canUndoSteps);
|
261
|
+
view.callbacks.on("onCanRedoStepsUpdate", redoListener);
|
262
|
+
view.callbacks.on("onCanUndoStepsUpdate", undoListener);
|
263
|
+
};
|
264
|
+
|
265
|
+
private onCanRedoStepsUpdate = (steps: number) => {
|
266
|
+
callbacks.emit("canRedoStepsChange", steps);
|
267
|
+
};
|
268
|
+
|
269
|
+
private onCanUndoStepsUpdate = (steps: number) => {
|
270
|
+
callbacks.emit("canUndoStepsChange", steps);
|
271
|
+
};
|
272
|
+
|
121
273
|
/**
|
122
274
|
* 插件更新 attributes 时的回调
|
123
275
|
*
|
@@ -133,19 +285,18 @@ export class AppManager {
|
|
133
285
|
createdAt: apps[appId].createdAt,
|
134
286
|
};
|
135
287
|
});
|
136
|
-
for (const { id } of
|
288
|
+
for (const { id } of orderBy(appsWithCreatedAt, "createdAt", "asc")) {
|
137
289
|
if (!this.appProxies.has(id) && !this.appStatus.has(id)) {
|
138
290
|
const app = apps[id];
|
139
291
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
await this.baseInsertApp(
|
292
|
+
this.appStatus.set(id, AppStatus.StartCreate);
|
293
|
+
try {
|
294
|
+
const appAttributes = this.attributes[id];
|
295
|
+
if (!appAttributes) {
|
296
|
+
throw new Error("appAttributes is undefined");
|
297
|
+
}
|
298
|
+
this.appCreateQueue.push(() => {
|
299
|
+
return this.baseInsertApp(
|
149
300
|
{
|
150
301
|
kind: app.kind,
|
151
302
|
options: app.options,
|
@@ -154,13 +305,11 @@ export class AppManager {
|
|
154
305
|
id,
|
155
306
|
false
|
156
307
|
);
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
this.appStatus.delete(id);
|
163
|
-
});
|
308
|
+
});
|
309
|
+
this.focusByAttributes(apps);
|
310
|
+
} catch (error) {
|
311
|
+
console.warn(`[WindowManager]: Insert App Error`, error);
|
312
|
+
}
|
164
313
|
}
|
165
314
|
}
|
166
315
|
}
|
@@ -201,10 +350,11 @@ export class AppManager {
|
|
201
350
|
emitter.emit("mainViewMounted");
|
202
351
|
}
|
203
352
|
|
204
|
-
public setMainViewFocusPath() {
|
205
|
-
const
|
206
|
-
if (
|
207
|
-
setViewFocusScenePath(this.mainView,
|
353
|
+
public setMainViewFocusPath(scenePath?: string) {
|
354
|
+
const focusScenePath = scenePath || this.store.getMainViewScenePath();
|
355
|
+
if (focusScenePath) {
|
356
|
+
const view = setViewFocusScenePath(this.mainView, focusScenePath);
|
357
|
+
return view?.focusScenePath === focusScenePath;
|
208
358
|
}
|
209
359
|
}
|
210
360
|
|
@@ -283,10 +433,6 @@ export class AppManager {
|
|
283
433
|
}
|
284
434
|
});
|
285
435
|
}
|
286
|
-
if (state.roomMembers) {
|
287
|
-
this.windowManger.cursorManager?.setRoomMembers(state.roomMembers);
|
288
|
-
this.windowManger.cursorManager?.cleanMemberAttributes(state.roomMembers);
|
289
|
-
}
|
290
436
|
this.appProxies.forEach(appProxy => {
|
291
437
|
appProxy.appEmitter.emit("roomStateChange", state);
|
292
438
|
});
|
@@ -307,37 +453,14 @@ export class AppManager {
|
|
307
453
|
});
|
308
454
|
if (isWritable === true) {
|
309
455
|
this.mainView.disableCameraTransform = false;
|
456
|
+
if (this.room && this.room.disableSerialization === true) {
|
457
|
+
this.room.disableSerialization = false;
|
458
|
+
}
|
310
459
|
} else {
|
311
460
|
this.mainView.disableCameraTransform = true;
|
312
461
|
}
|
313
462
|
};
|
314
463
|
|
315
|
-
private get eventName() {
|
316
|
-
return isRoom(this.displayer) ? "onRoomStateChanged" : "onPlayerStateChanged";
|
317
|
-
}
|
318
|
-
|
319
|
-
public get attributes() {
|
320
|
-
return this.windowManger.attributes;
|
321
|
-
}
|
322
|
-
|
323
|
-
public get canOperate() {
|
324
|
-
return this.windowManger.canOperate;
|
325
|
-
}
|
326
|
-
|
327
|
-
public get room() {
|
328
|
-
return isRoom(this.displayer) ? (this.displayer as Room) : undefined;
|
329
|
-
}
|
330
|
-
|
331
|
-
public get mainView() {
|
332
|
-
return this.mainViewProxy.view;
|
333
|
-
}
|
334
|
-
|
335
|
-
public get focusApp() {
|
336
|
-
if (this.store.focus) {
|
337
|
-
return this.appProxies.get(this.store.focus);
|
338
|
-
}
|
339
|
-
}
|
340
|
-
|
341
464
|
public safeSetAttributes(attributes: any) {
|
342
465
|
this.windowManger.safeSetAttributes(attributes);
|
343
466
|
}
|
@@ -349,6 +472,10 @@ export class AppManager {
|
|
349
472
|
public async setMainViewScenePath(scenePath: string) {
|
350
473
|
if (this.room) {
|
351
474
|
const scenePathType = this.displayer.scenePathType(scenePath);
|
475
|
+
const sceneDir = parseSceneDir(scenePath);
|
476
|
+
if (sceneDir !== ROOT_DIR) {
|
477
|
+
throw new Error(`[WindowManager]: main view scenePath must in root dir "/"`);
|
478
|
+
}
|
352
479
|
if (scenePathType === ScenePathType.None) {
|
353
480
|
throw new Error(`[WindowManager]: ${scenePath} not valid scene`);
|
354
481
|
} else if (scenePathType === ScenePathType.Page) {
|
@@ -363,32 +490,56 @@ export class AppManager {
|
|
363
490
|
}
|
364
491
|
|
365
492
|
private async _setMainViewScenePath(scenePath: string) {
|
366
|
-
this.
|
367
|
-
|
368
|
-
|
369
|
-
|
493
|
+
const success = this.setMainViewFocusPath(scenePath);
|
494
|
+
if (success) {
|
495
|
+
this.safeSetAttributes({ _mainScenePath: scenePath });
|
496
|
+
this.store.setMainViewFocusPath(this.mainView);
|
497
|
+
this.updateSceneIndex();
|
498
|
+
this.dispatchSetMainViewScenePath(scenePath);
|
499
|
+
}
|
370
500
|
}
|
371
501
|
|
502
|
+
private updateSceneIndex = () => {
|
503
|
+
const scenePath = this.store.getMainViewScenePath() as string;
|
504
|
+
const sceneDir = parseSceneDir(scenePath);
|
505
|
+
const scenes = entireScenes(this.displayer)[sceneDir];
|
506
|
+
if (scenes.length) {
|
507
|
+
// "/ppt3/1" -> "1"
|
508
|
+
const pageName = scenePath.replace(sceneDir, "").replace("/", "");
|
509
|
+
const index = scenes.findIndex(scene => scene.name === pageName);
|
510
|
+
if (isInteger(index) && index >= 0) {
|
511
|
+
this.safeSetAttributes({ _mainSceneIndex: index });
|
512
|
+
}
|
513
|
+
}
|
514
|
+
};
|
515
|
+
|
372
516
|
public async setMainViewSceneIndex(index: number) {
|
373
517
|
if (this.room) {
|
374
|
-
this.
|
518
|
+
if (this.store.getMainViewSceneIndex() === index) return;
|
375
519
|
const mainViewScenePath = this.store.getMainViewScenePath() as string;
|
376
520
|
if (mainViewScenePath) {
|
377
|
-
const
|
378
|
-
sceneList.pop();
|
379
|
-
let sceneDir = sceneList.join("/");
|
380
|
-
if (sceneDir === "") {
|
381
|
-
sceneDir = "/";
|
382
|
-
}
|
521
|
+
const sceneDir = parseSceneDir(mainViewScenePath);
|
383
522
|
const scenePath = makeValidScenePath(this.displayer, sceneDir, index);
|
384
523
|
if (scenePath) {
|
385
|
-
this.
|
386
|
-
|
524
|
+
const success = this.setMainViewFocusPath(scenePath);
|
525
|
+
if (success) {
|
526
|
+
this.store.setMainViewScenePath(scenePath);
|
527
|
+
this.safeSetAttributes({ _mainSceneIndex: index });
|
528
|
+
this.dispatchSetMainViewScenePath(scenePath);
|
529
|
+
}
|
530
|
+
} else {
|
531
|
+
throw new Error(`[WindowManager]: ${sceneDir}: ${index} not valid index`);
|
387
532
|
}
|
388
533
|
}
|
389
534
|
}
|
390
535
|
}
|
391
536
|
|
537
|
+
private dispatchSetMainViewScenePath(scenePath: string): void {
|
538
|
+
this.dispatchInternalEvent(Events.SetMainViewScenePath, { nextScenePath: scenePath });
|
539
|
+
// 兼容 15 的 SDK, 需要 room 的当前 ScenePath
|
540
|
+
setScenePath(this.room, scenePath);
|
541
|
+
}
|
542
|
+
|
392
543
|
public getAppInitPath(appId: string): string | undefined {
|
393
544
|
const attrs = this.store.getAppAttributes(appId);
|
394
545
|
if (attrs) {
|
@@ -456,6 +607,7 @@ export class AppManager {
|
|
456
607
|
const reconnected = appProxies.map(appProxy => {
|
457
608
|
return appProxy.onReconnected();
|
458
609
|
});
|
610
|
+
this.mainViewProxy.onReconnect();
|
459
611
|
await Promise.all(reconnected);
|
460
612
|
}
|
461
613
|
|
@@ -472,6 +624,11 @@ export class AppManager {
|
|
472
624
|
});
|
473
625
|
}
|
474
626
|
|
627
|
+
public findMemberByUid = (uid: string) => {
|
628
|
+
const roomMembers = this.room?.state.roomMembers;
|
629
|
+
return roomMembers?.find(member => member.payload?.uid === uid);
|
630
|
+
};
|
631
|
+
|
475
632
|
public destroy() {
|
476
633
|
this.displayer.callbacks.off(this.eventName, this.displayerStateListener);
|
477
634
|
this.displayer.callbacks.off("onEnableWriteNowChanged", this.displayerWritableListener);
|
@@ -488,6 +645,10 @@ export class AppManager {
|
|
488
645
|
this.refresher?.destroy();
|
489
646
|
this.mainViewProxy.destroy();
|
490
647
|
callbacks.clearListeners();
|
648
|
+
this.callbacksNode?.dispose();
|
649
|
+
this.appCreateQueue.destroy();
|
650
|
+
this.disposePrevFocusViewRedoUndoListeners(this._prevFocused);
|
651
|
+
this._prevFocused = undefined;
|
491
652
|
this._prevSceneIndex = undefined;
|
492
653
|
}
|
493
654
|
}
|