@netless/window-manager 1.0.0-canary.1 → 1.0.0-canary.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/dist/App/AppContext.d.ts +14 -15
- package/dist/App/AppPageStateImpl.d.ts +6 -2
- package/dist/App/AppProxy.d.ts +5 -1
- package/dist/App/WhiteBoardView.d.ts +16 -0
- package/dist/App/index.d.ts +1 -0
- package/dist/AppManager.d.ts +2 -0
- package/dist/Helper.d.ts +12 -2
- package/dist/InternalEmitter.d.ts +2 -0
- package/dist/constants.d.ts +1 -0
- package/dist/index.cjs.js +12 -12
- package/dist/index.es.js +215 -388
- package/dist/index.umd.js +12 -12
- package/dist/typings.d.ts +4 -0
- package/package.json +2 -1
- package/pnpm-lock.yaml +2 -0
- package/src/App/AppContext.ts +57 -72
- package/src/App/AppPageStateImpl.ts +25 -6
- package/src/App/AppProxy.ts +39 -6
- package/src/App/Storage/index.ts +4 -4
- package/src/App/WhiteBoardView.ts +68 -0
- package/src/App/index.ts +1 -0
- package/src/AppManager.ts +9 -1
- package/src/Helper.ts +10 -1
- package/src/InternalEmitter.ts +2 -0
- package/src/constants.ts +2 -0
- package/src/typings.ts +4 -0
package/dist/typings.d.ts
CHANGED
@@ -3,6 +3,7 @@ import type { AnimationMode, ApplianceNames, Displayer, DisplayerState, Player,
|
|
3
3
|
import type { AppContext } from "./App";
|
4
4
|
import type { ReadonlyTeleBox, TeleBoxRect } from "@netless/telebox-insider";
|
5
5
|
import type { PageState } from "./Page";
|
6
|
+
import type { Member } from "./Helper";
|
6
7
|
export interface NetlessApp<Attributes = any, MagixEventPayloads = any, AppOptions = any, SetupResult = any> {
|
7
8
|
kind: string;
|
8
9
|
config?: {
|
@@ -49,6 +50,7 @@ export declare type AppEmitterEvent<T = any> = {
|
|
49
50
|
reconnected: void;
|
50
51
|
seek: number;
|
51
52
|
pageStateChange: PageState;
|
53
|
+
roomMembersChange: Member[];
|
52
54
|
};
|
53
55
|
export declare type RegisterEventData = {
|
54
56
|
appId: string;
|
@@ -71,8 +73,10 @@ export declare type RegisterParams<AppOptions = any, SetupResult = any, Attribut
|
|
71
73
|
export declare type AppListenerKeys = keyof AppEmitterEvent;
|
72
74
|
export declare type ApplianceIcons = Partial<Record<ApplianceNames, string>>;
|
73
75
|
export type { AppContext } from "./App/AppContext";
|
76
|
+
export type { WhiteBoardView } from "./App";
|
74
77
|
export type { ReadonlyTeleBox, TeleBoxRect };
|
75
78
|
export type { SceneState, SceneDefinition, View, AnimationMode, Displayer, Room, Player };
|
76
79
|
export type { Storage, StorageStateChangedEvent, StorageStateChangedListener } from "./App/Storage";
|
77
80
|
export * from "./Page";
|
78
81
|
export * from "./Utils/error";
|
82
|
+
export type { Member } from "./Helper";
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@netless/window-manager",
|
3
|
-
"version": "1.0.0-canary.
|
3
|
+
"version": "1.0.0-canary.2",
|
4
4
|
"description": "",
|
5
5
|
"main": "dist/index.cjs.js",
|
6
6
|
"module": "dist/index.es.js",
|
@@ -29,6 +29,7 @@
|
|
29
29
|
"p-retry": "^4.6.1",
|
30
30
|
"side-effect-manager": "^1.1.0",
|
31
31
|
"uuid": "^7.0.3",
|
32
|
+
"value-enhancer": "^1.2.1",
|
32
33
|
"video.js": ">=7"
|
33
34
|
},
|
34
35
|
"devDependencies": {
|
package/pnpm-lock.yaml
CHANGED
@@ -35,6 +35,7 @@ specifiers:
|
|
35
35
|
svelte: ^3.42.4
|
36
36
|
typescript: ^4.5.5
|
37
37
|
uuid: ^7.0.3
|
38
|
+
value-enhancer: ^1.2.1
|
38
39
|
video.js: '>=7'
|
39
40
|
vite: ^2.5.3
|
40
41
|
vitest: ^0.14.1
|
@@ -48,6 +49,7 @@ dependencies:
|
|
48
49
|
p-retry: registry.npmmirror.com/p-retry/4.6.1
|
49
50
|
side-effect-manager: 1.1.0
|
50
51
|
uuid: registry.npmmirror.com/uuid/7.0.3
|
52
|
+
value-enhancer: 1.2.1
|
51
53
|
video.js: registry.npmmirror.com/video.js/7.18.1
|
52
54
|
|
53
55
|
devDependencies:
|
package/src/App/AppContext.ts
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import { BoxNotCreatedError } from "../Utils/error";
|
2
|
-
import { putScenes } from "../Utils/Common";
|
3
2
|
import { Storage } from "./Storage";
|
4
3
|
import {
|
5
4
|
autorun,
|
@@ -19,7 +18,7 @@ import type {
|
|
19
18
|
import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
20
19
|
import type Emittery from "emittery";
|
21
20
|
import type { BoxManager } from "../BoxManager";
|
22
|
-
import type { AppEmitterEvent } from "../index";
|
21
|
+
import type { AppEmitterEvent, Member } from "../index";
|
23
22
|
import type { AppManager } from "../AppManager";
|
24
23
|
import type { AppProxy } from "./AppProxy";
|
25
24
|
import type {
|
@@ -27,11 +26,13 @@ import type {
|
|
27
26
|
MagixEventDispatcher,
|
28
27
|
MagixEventRemoveListener,
|
29
28
|
} from "./MagixEvent";
|
30
|
-
import
|
29
|
+
import { WhiteBoardView } from "./WhiteBoardView";
|
30
|
+
import { findMemberByUid } from "../Helper";
|
31
|
+
import { MAX_PAGE_SIZE } from "../constants";
|
32
|
+
import { putScenes } from "../Utils/Common";
|
33
|
+
import { isNumber } from "lodash";
|
31
34
|
|
32
|
-
export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOptions = any>
|
33
|
-
implements PageController
|
34
|
-
{
|
35
|
+
export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOptions = any> {
|
35
36
|
public readonly emitter: Emittery<AppEmitterEvent<TAttributes>>;
|
36
37
|
public readonly mobxUtils = {
|
37
38
|
autorun,
|
@@ -48,6 +49,7 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
48
49
|
private store = this.manager.store;
|
49
50
|
public readonly isAddApp: boolean;
|
50
51
|
public readonly isReplay = this.manager.isReplay;
|
52
|
+
private whiteBoardView?: WhiteBoardView;
|
51
53
|
|
52
54
|
constructor(
|
53
55
|
private manager: AppManager,
|
@@ -60,7 +62,7 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
60
62
|
this.isAddApp = appProxy.isAddApp;
|
61
63
|
}
|
62
64
|
|
63
|
-
public
|
65
|
+
public get displayer(){
|
64
66
|
return this.manager.displayer;
|
65
67
|
};
|
66
68
|
|
@@ -78,32 +80,50 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
78
80
|
}
|
79
81
|
};
|
80
82
|
|
81
|
-
public
|
83
|
+
public get view(): View | undefined {
|
82
84
|
return this.appProxy.view;
|
83
85
|
};
|
84
86
|
|
85
|
-
public
|
86
|
-
|
87
|
-
|
88
|
-
view.divElement = dom as HTMLDivElement;
|
89
|
-
setTimeout(() => {
|
90
|
-
// 渲染需要时间,延迟 refresh
|
91
|
-
this.getRoom()?.refreshViewSize();
|
92
|
-
}, 1000);
|
87
|
+
public createWhiteBoardView = (size?: number): WhiteBoardView => {
|
88
|
+
if (this.whiteBoardView) {
|
89
|
+
return this.whiteBoardView;
|
93
90
|
}
|
94
|
-
|
91
|
+
let view = this.view;
|
92
|
+
if (!view) {
|
93
|
+
view = this.appProxy.createAppDir();
|
94
|
+
}
|
95
|
+
view.divElement = this.box.$content as HTMLDivElement;
|
96
|
+
this.initPageSize(size);
|
97
|
+
this.whiteBoardView = new WhiteBoardView(this, this.appProxy);
|
98
|
+
return this.whiteBoardView;
|
99
|
+
}
|
100
|
+
|
101
|
+
private initPageSize = (size?: number) => {
|
102
|
+
if (!isNumber(size)) return;
|
103
|
+
if (!this.appProxy.scenePath) return;
|
104
|
+
if (this.appProxy.pageState.length >= size) return;
|
105
|
+
if (size <= 0 || size >= MAX_PAGE_SIZE) {
|
106
|
+
throw Error(`[WindowManager]: size ${size} muse be in range [1, ${MAX_PAGE_SIZE}]`);
|
107
|
+
}
|
108
|
+
const needInsert = size - this.appProxy.pageState.length;
|
109
|
+
const startPageNumber = this.appProxy.pageState.length;
|
110
|
+
const scenes = new Array(needInsert).fill({}).map((_, index) => {
|
111
|
+
return { name: `${startPageNumber + index + 1}` };
|
112
|
+
});
|
113
|
+
putScenes(this.room, this.appProxy.scenePath, scenes);
|
114
|
+
}
|
95
115
|
|
96
116
|
public getInitScenePath = () => {
|
97
117
|
return this.manager.getAppInitPath(this.appId);
|
98
118
|
};
|
99
119
|
|
100
120
|
/** Get App writable status. */
|
101
|
-
public
|
121
|
+
public get isWritable(): boolean {
|
102
122
|
return this.manager.canOperate;
|
103
123
|
};
|
104
124
|
|
105
125
|
/** Get the App Window UI box. */
|
106
|
-
public
|
126
|
+
public get box(): ReadonlyTeleBox {
|
107
127
|
const box = this.boxManager.getBox(this.appId);
|
108
128
|
if (box) {
|
109
129
|
return box;
|
@@ -112,10 +132,25 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
112
132
|
}
|
113
133
|
};
|
114
134
|
|
115
|
-
public
|
135
|
+
public get room(): Room | undefined {
|
116
136
|
return this.manager.room;
|
117
137
|
};
|
118
138
|
|
139
|
+
public get members() {
|
140
|
+
return this.manager.members;
|
141
|
+
}
|
142
|
+
|
143
|
+
public get memberState(): Member {
|
144
|
+
const self = findMemberByUid(this.room, this.manager.uid);
|
145
|
+
if (!self) {
|
146
|
+
throw new Error(`Member ${this.manager.uid} not found.`);
|
147
|
+
}
|
148
|
+
return {
|
149
|
+
uid: this.manager.uid,
|
150
|
+
...self,
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
119
154
|
/** @deprecated Use context.storage.setState instead. */
|
120
155
|
public setAttributes = (attributes: TAttributes) => {
|
121
156
|
this.manager.safeSetAttributes({ [this.appId]: attributes });
|
@@ -128,11 +163,12 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
128
163
|
}
|
129
164
|
};
|
130
165
|
|
166
|
+
/** @deprecated Use Pages api instead. */
|
131
167
|
public setScenePath = async (scenePath: string): Promise<void> => {
|
132
168
|
if (!this.appProxy.box) return;
|
133
169
|
this.appProxy.setFullPath(scenePath);
|
134
170
|
// 兼容 15 版本 SDK 的切页
|
135
|
-
this.
|
171
|
+
this.room?.setScenePath(scenePath);
|
136
172
|
};
|
137
173
|
|
138
174
|
/** Get the local App options. */
|
@@ -196,55 +232,4 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
196
232
|
public removeMagixEventListener = this.manager.displayer.removeMagixEventListener.bind(
|
197
233
|
this.manager.displayer
|
198
234
|
) as MagixEventRemoveListener<TMagixEventPayloads>;
|
199
|
-
|
200
|
-
/** PageController */
|
201
|
-
public nextPage = async (): Promise<boolean> => {
|
202
|
-
const nextIndex = this.pageState.index + 1;
|
203
|
-
if (nextIndex > this.pageState.length - 1) {
|
204
|
-
console.warn("[WindowManager] nextPage: index out of range");
|
205
|
-
return false;
|
206
|
-
}
|
207
|
-
this.appProxy.setSceneIndex(nextIndex);
|
208
|
-
return true;
|
209
|
-
};
|
210
|
-
|
211
|
-
public prevPage = async (): Promise<boolean> => {
|
212
|
-
const nextIndex = this.pageState.index - 1;
|
213
|
-
if (nextIndex < 0) {
|
214
|
-
console.warn("[WindowManager] prevPage: index out of range");
|
215
|
-
return false;
|
216
|
-
}
|
217
|
-
this.appProxy.setSceneIndex(nextIndex);
|
218
|
-
return true;
|
219
|
-
};
|
220
|
-
|
221
|
-
public addPage = async (params?: AddPageParams) => {
|
222
|
-
const after = params?.after;
|
223
|
-
const scene = params?.scene;
|
224
|
-
const scenePath = this.appProxy.scenePath;
|
225
|
-
if (!scenePath) return;
|
226
|
-
if (after) {
|
227
|
-
const nextIndex = this.pageState.index + 1;
|
228
|
-
putScenes(this.manager.room, scenePath, [scene || {}], nextIndex);
|
229
|
-
} else {
|
230
|
-
putScenes(this.manager.room, scenePath, [scene || {}]);
|
231
|
-
}
|
232
|
-
};
|
233
|
-
|
234
|
-
public removePage = async (index?: number): Promise<boolean> => {
|
235
|
-
const needRemoveIndex = index === undefined ? this.pageState.index : index;
|
236
|
-
if (this.pageState.length === 1) {
|
237
|
-
console.warn(`[WindowManager]: can not remove the last page`);
|
238
|
-
return false;
|
239
|
-
}
|
240
|
-
if (needRemoveIndex < 0 || needRemoveIndex >= this.pageState.length) {
|
241
|
-
console.warn(`[WindowManager]: page index ${index} out of range`);
|
242
|
-
return false;
|
243
|
-
}
|
244
|
-
return this.appProxy.removeSceneByIndex(needRemoveIndex);;
|
245
|
-
}
|
246
|
-
|
247
|
-
public get pageState(): PageState {
|
248
|
-
return this.appProxy.pageState;
|
249
|
-
}
|
250
235
|
}
|
@@ -9,11 +9,15 @@ export type AppPageStateParams = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
export class AppPageStateImpl {
|
12
|
-
|
12
|
+
public sceneNode: ScenesCallbacksNode | null = null;
|
13
|
+
private scenePath?: string;
|
14
|
+
private view?: View;
|
13
15
|
|
14
16
|
constructor(private params: AppPageStateParams) {
|
15
17
|
const { displayer, scenePath } = this.params;
|
18
|
+
this.view = this.params.view;
|
16
19
|
if (scenePath) {
|
20
|
+
this.scenePath = scenePath;
|
17
21
|
this.sceneNode = displayer.createScenesCallback(scenePath, {
|
18
22
|
onAddScene: this.onSceneChange,
|
19
23
|
onRemoveScene: this.onSceneChange,
|
@@ -21,24 +25,39 @@ export class AppPageStateImpl {
|
|
21
25
|
}
|
22
26
|
}
|
23
27
|
|
24
|
-
|
25
|
-
this.
|
28
|
+
public createSceneNode = (scenePath: string) => {
|
29
|
+
this.scenePath = scenePath;
|
30
|
+
if (this.sceneNode) {
|
31
|
+
this.sceneNode.dispose();
|
32
|
+
}
|
33
|
+
this.sceneNode = this.params.displayer.createScenesCallback(scenePath, {
|
34
|
+
onAddScene: this.onSceneChange,
|
35
|
+
onRemoveScene: this.onSceneChange,
|
36
|
+
});
|
37
|
+
return this.sceneNode;
|
38
|
+
}
|
39
|
+
|
40
|
+
public setView(view: View) {
|
41
|
+
this.view = view;
|
42
|
+
}
|
43
|
+
|
44
|
+
private onSceneChange = () => {
|
26
45
|
this.params.notifyPageStateChange();
|
27
46
|
};
|
28
47
|
|
29
48
|
public getFullPath(index: number) {
|
30
49
|
const scenes = this.sceneNode?.scenes;
|
31
|
-
if (this.
|
50
|
+
if (this.scenePath && scenes) {
|
32
51
|
const name = scenes[index];
|
33
52
|
if (name) {
|
34
|
-
return `${this.
|
53
|
+
return `${this.scenePath}/${name}`;
|
35
54
|
}
|
36
55
|
}
|
37
56
|
}
|
38
57
|
|
39
58
|
public toObject(): PageState {
|
40
59
|
return {
|
41
|
-
index: this.
|
60
|
+
index: this.view?.focusSceneIndex || 0,
|
42
61
|
length: this.sceneNode?.scenes.length || 0,
|
43
62
|
};
|
44
63
|
}
|
package/src/App/AppProxy.ts
CHANGED
@@ -12,6 +12,7 @@ import { log } from "../Utils/log";
|
|
12
12
|
import {
|
13
13
|
entireScenes,
|
14
14
|
getScenePath,
|
15
|
+
putScenes,
|
15
16
|
removeScenes,
|
16
17
|
setScenePath,
|
17
18
|
setViewFocusScenePath,
|
@@ -30,6 +31,7 @@ import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
|
30
31
|
import type { PageRemoveService, PageState } from "../Page";
|
31
32
|
import { calculateNextIndex } from "../Page";
|
32
33
|
import { boxEmitter } from "../BoxEmitter";
|
34
|
+
import { SideEffectManager } from "side-effect-manager";
|
33
35
|
|
34
36
|
export type AppEmitter = Emittery<AppEmitterEvent>;
|
35
37
|
|
@@ -37,6 +39,7 @@ export class AppProxy implements PageRemoveService {
|
|
37
39
|
public kind: string;
|
38
40
|
public id: string;
|
39
41
|
public scenePath?: string;
|
42
|
+
private appScenePath: string;
|
40
43
|
public appEmitter: AppEmitter;
|
41
44
|
public scenes?: SceneDefinition[];
|
42
45
|
|
@@ -49,12 +52,14 @@ export class AppProxy implements PageRemoveService {
|
|
49
52
|
public isAddApp: boolean;
|
50
53
|
private status: "normal" | "destroyed" = "normal";
|
51
54
|
private stateKey: string;
|
52
|
-
|
55
|
+
public _pageState: AppPageStateImpl;
|
53
56
|
private _prevFullPath: string | undefined;
|
54
57
|
|
55
58
|
public appResult?: NetlessApp<any>;
|
56
59
|
public appContext?: AppContext<any, any>;
|
57
60
|
|
61
|
+
private sideEffectManager = new SideEffectManager();
|
62
|
+
|
58
63
|
constructor(
|
59
64
|
private params: BaseInsertParams,
|
60
65
|
private manager: AppManager,
|
@@ -63,6 +68,7 @@ export class AppProxy implements PageRemoveService {
|
|
63
68
|
) {
|
64
69
|
this.kind = params.kind;
|
65
70
|
this.id = appId;
|
71
|
+
this.appScenePath = `/${this.id}-app-dir`;
|
66
72
|
this.stateKey = `${this.id}_state`;
|
67
73
|
this.appProxies.set(this.id, this);
|
68
74
|
this.appEmitter = new Emittery();
|
@@ -75,12 +81,37 @@ export class AppProxy implements PageRemoveService {
|
|
75
81
|
// 只有传入了 scenePath 的 App 才会创建 View
|
76
82
|
this.createView();
|
77
83
|
}
|
84
|
+
if (!this.scenePath) {
|
85
|
+
this.scenePath = this.appScenePath;
|
86
|
+
}
|
78
87
|
this._pageState = new AppPageStateImpl({
|
79
88
|
displayer: this.manager.displayer,
|
80
89
|
scenePath: this.scenePath,
|
81
90
|
view: this.view,
|
82
91
|
notifyPageStateChange: this.notifyPageStateChange,
|
83
92
|
});
|
93
|
+
this.sideEffectManager.add(() => {
|
94
|
+
return () => this._pageState.destroy();
|
95
|
+
});
|
96
|
+
this.sideEffectManager.add(() => {
|
97
|
+
return emitter.on("roomMembersChange", members => {
|
98
|
+
this.appEmitter.emit("roomMembersChange", members);
|
99
|
+
});
|
100
|
+
});
|
101
|
+
}
|
102
|
+
|
103
|
+
public createAppDir() {
|
104
|
+
const scenePath = this.scenePath || this.appScenePath;
|
105
|
+
const sceneNode = this._pageState.createSceneNode(scenePath);
|
106
|
+
if (!sceneNode) {
|
107
|
+
putScenes(this.manager.room, scenePath, [{ name: "1" }]);
|
108
|
+
this._pageState.createSceneNode(scenePath);
|
109
|
+
this.setSceneIndex(0);
|
110
|
+
}
|
111
|
+
this.scenes = entireScenes(this.manager.displayer)[scenePath];
|
112
|
+
const view = this.createView();
|
113
|
+
this._pageState.setView(view);
|
114
|
+
return view;
|
84
115
|
}
|
85
116
|
|
86
117
|
private initScenes() {
|
@@ -395,14 +426,16 @@ export class AppProxy implements PageRemoveService {
|
|
395
426
|
return fullPath;
|
396
427
|
}
|
397
428
|
|
398
|
-
private
|
399
|
-
const view =
|
429
|
+
private createView(): View {
|
430
|
+
const view = this.viewManager.createView(this.id);
|
400
431
|
this.setViewFocusScenePath();
|
401
432
|
return view;
|
402
433
|
}
|
403
434
|
|
404
435
|
public notifyPageStateChange = debounce(() => {
|
405
|
-
|
436
|
+
if (this.pageState) {
|
437
|
+
this.appEmitter.emit("pageStateChange", this.pageState);
|
438
|
+
}
|
406
439
|
}, 50);
|
407
440
|
|
408
441
|
public get pageState(): PageState {
|
@@ -412,7 +445,7 @@ export class AppProxy implements PageRemoveService {
|
|
412
445
|
// PageRemoveService
|
413
446
|
public async removeSceneByIndex(index: number) {
|
414
447
|
const scenePath = this._pageState.getFullPath(index);
|
415
|
-
if (scenePath) {
|
448
|
+
if (scenePath && this.pageState) {
|
416
449
|
const nextIndex = calculateNextIndex(index, this.pageState);
|
417
450
|
// 只修改 focus path 不修改 FullPath
|
418
451
|
this.setSceneIndexWithoutSync(nextIndex);
|
@@ -474,7 +507,6 @@ export class AppProxy implements PageRemoveService {
|
|
474
507
|
}
|
475
508
|
}
|
476
509
|
this.appProxies.delete(this.id);
|
477
|
-
this._pageState.destroy();
|
478
510
|
|
479
511
|
this.viewManager.destroyView(this.id);
|
480
512
|
this.manager.appStatus.delete(this.id);
|
@@ -482,6 +514,7 @@ export class AppProxy implements PageRemoveService {
|
|
482
514
|
this.manager.refresher?.remove(this.stateKey);
|
483
515
|
this.manager.refresher?.remove(`${this.id}-fullPath`);
|
484
516
|
this._prevFullPath = undefined;
|
517
|
+
this.sideEffectManager.flushAll();
|
485
518
|
}
|
486
519
|
|
487
520
|
public close(): Promise<void> {
|
package/src/App/Storage/index.ts
CHANGED
@@ -37,7 +37,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
|
|
37
37
|
this._state = {} as TState;
|
38
38
|
const rawState = this._getRawState(this._state);
|
39
39
|
|
40
|
-
if (this._context.
|
40
|
+
if (this._context.isWritable) {
|
41
41
|
if (this.id === null) {
|
42
42
|
if (context.isAddApp && defaultState) {
|
43
43
|
this.setState(defaultState);
|
@@ -115,7 +115,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
|
|
115
115
|
return;
|
116
116
|
}
|
117
117
|
|
118
|
-
if (!this._context.
|
118
|
+
if (!this._context.isWritable) {
|
119
119
|
console.error(new Error(`Cannot setState on Storage "${this.id}" without writable access`), state);
|
120
120
|
return;
|
121
121
|
}
|
@@ -165,7 +165,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
|
|
165
165
|
return;
|
166
166
|
}
|
167
167
|
|
168
|
-
if (!this._context.
|
168
|
+
if (!this._context.isWritable) {
|
169
169
|
console.error(new Error(`Cannot empty Storage "${this.id}" without writable access.`));
|
170
170
|
return;
|
171
171
|
}
|
@@ -181,7 +181,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
|
|
181
181
|
throw new Error(`Cannot delete main Storage`);
|
182
182
|
}
|
183
183
|
|
184
|
-
if (!this._context.
|
184
|
+
if (!this._context.isWritable) {
|
185
185
|
console.error(new Error(`Cannot delete Storage "${this.id}" without writable access.`));
|
186
186
|
return;
|
187
187
|
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import { putScenes } from "../Utils/Common";
|
2
|
+
import { Val } from "value-enhancer";
|
3
|
+
|
4
|
+
import type { ReadonlyVal } from "value-enhancer";
|
5
|
+
import type { AddPageParams, PageController, PageState } from "../Page";
|
6
|
+
import type { AppProxy } from "./AppProxy";
|
7
|
+
import type { AppContext } from "./AppContext";
|
8
|
+
|
9
|
+
export class WhiteBoardView implements PageController {
|
10
|
+
public readonly pageState$: ReadonlyVal<PageState>;
|
11
|
+
|
12
|
+
constructor(protected appContext: AppContext, protected appProxy: AppProxy) {
|
13
|
+
const pageState$ = new Val<PageState>(appProxy.pageState);
|
14
|
+
this.pageState$ = pageState$;
|
15
|
+
appProxy.appEmitter.on("pageStateChange", pageState => {
|
16
|
+
pageState$.setValue(pageState);
|
17
|
+
});
|
18
|
+
}
|
19
|
+
|
20
|
+
public get pageState() {
|
21
|
+
return this.pageState$.value;
|
22
|
+
}
|
23
|
+
|
24
|
+
public nextPage = async (): Promise<boolean> => {
|
25
|
+
const nextIndex = this.pageState.index + 1;
|
26
|
+
return this.jumpPage(nextIndex);
|
27
|
+
};
|
28
|
+
|
29
|
+
public prevPage = async (): Promise<boolean> => {
|
30
|
+
const nextIndex = this.pageState.index - 1;
|
31
|
+
return this.jumpPage(nextIndex);
|
32
|
+
};
|
33
|
+
|
34
|
+
public jumpPage = async (index: number): Promise<boolean> => {
|
35
|
+
if (index < 0 || index >= this.pageState.length) {
|
36
|
+
console.warn(`[WindowManager]: index ${index} out of range`);
|
37
|
+
return false;
|
38
|
+
}
|
39
|
+
this.appProxy.setSceneIndex(index);
|
40
|
+
return true;
|
41
|
+
};
|
42
|
+
|
43
|
+
public addPage = async (params?: AddPageParams) => {
|
44
|
+
const after = params?.after;
|
45
|
+
const scene = params?.scene;
|
46
|
+
const scenePath = this.appProxy.scenePath;
|
47
|
+
if (!scenePath) return;
|
48
|
+
if (after) {
|
49
|
+
const nextIndex = this.pageState.index + 1;
|
50
|
+
putScenes(this.appContext.room, scenePath, [scene || {}], nextIndex);
|
51
|
+
} else {
|
52
|
+
putScenes(this.appContext.room, scenePath, [scene || {}]);
|
53
|
+
}
|
54
|
+
};
|
55
|
+
|
56
|
+
public removePage = async (index?: number): Promise<boolean> => {
|
57
|
+
const needRemoveIndex = index === undefined ? this.pageState.index : index;
|
58
|
+
if (this.pageState.length === 1) {
|
59
|
+
console.warn(`[WindowManager]: can not remove the last page`);
|
60
|
+
return false;
|
61
|
+
}
|
62
|
+
if (needRemoveIndex < 0 || needRemoveIndex >= this.pageState.length) {
|
63
|
+
console.warn(`[WindowManager]: page index ${index} out of range`);
|
64
|
+
return false;
|
65
|
+
}
|
66
|
+
return this.appProxy.removeSceneByIndex(needRemoveIndex);
|
67
|
+
};
|
68
|
+
}
|
package/src/App/index.ts
CHANGED
package/src/AppManager.ts
CHANGED
@@ -15,6 +15,7 @@ import { MainViewProxy } from "./View/MainView";
|
|
15
15
|
import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
|
16
16
|
import { reconnectRefresher, WindowManager } from "./index";
|
17
17
|
import { RedoUndo } from "./RedoUndo";
|
18
|
+
import { serializeRoomMembers } from "./Helper";
|
18
19
|
import { SideEffectManager } from "side-effect-manager";
|
19
20
|
import { ViewManager } from "./View/ViewManager";
|
20
21
|
import type { SyncRegisterAppPayload } from "./Register";
|
@@ -46,7 +47,7 @@ import type {
|
|
46
47
|
BoxResizePayload,
|
47
48
|
BoxStateChangePayload,
|
48
49
|
} from "./BoxEmitter";
|
49
|
-
|
50
|
+
import type { Member } from "./Helper";
|
50
51
|
|
51
52
|
export class AppManager {
|
52
53
|
public displayer: Displayer;
|
@@ -299,6 +300,10 @@ export class AppManager {
|
|
299
300
|
return this.room?.uid || "";
|
300
301
|
}
|
301
302
|
|
303
|
+
public get members(): Member[] {
|
304
|
+
return serializeRoomMembers(this.displayer.state.roomMembers);
|
305
|
+
}
|
306
|
+
|
302
307
|
public getMainViewSceneDir() {
|
303
308
|
const scenePath = this.store.getMainViewScenePath();
|
304
309
|
if (scenePath) {
|
@@ -660,6 +665,9 @@ export class AppManager {
|
|
660
665
|
this.appProxies.forEach(appProxy => {
|
661
666
|
appProxy.appEmitter.emit("roomStateChange", state);
|
662
667
|
});
|
668
|
+
if (state.roomMembers) {
|
669
|
+
emitter.emit("roomMembersChange", this.members);
|
670
|
+
}
|
663
671
|
emitter.emit("observerIdChange", this.displayer.observerId);
|
664
672
|
};
|
665
673
|
|
package/src/Helper.ts
CHANGED
@@ -2,7 +2,7 @@ import { getVersionNumber } from "./Utils/Common";
|
|
2
2
|
import { REQUIRE_VERSION } from "./constants";
|
3
3
|
import { WhiteVersion } from "white-web-sdk";
|
4
4
|
import { WhiteWebSDKInvalidError } from "./Utils/error";
|
5
|
-
import type { Room } from "white-web-sdk";
|
5
|
+
import type { Room , RoomMember} from "white-web-sdk";
|
6
6
|
|
7
7
|
export const setupWrapper = (
|
8
8
|
root: HTMLElement
|
@@ -32,3 +32,12 @@ export const findMemberByUid = (room: Room | undefined, uid: string) => {
|
|
32
32
|
const roomMembers = room?.state.roomMembers;
|
33
33
|
return roomMembers?.find(member => member.payload?.uid === uid);
|
34
34
|
};
|
35
|
+
|
36
|
+
export type Member = RoomMember & { uid: string };
|
37
|
+
|
38
|
+
export const serializeRoomMembers = (members: readonly RoomMember[]) => {
|
39
|
+
return members.map(member => ({
|
40
|
+
uid: member.payload?.uid || "",
|
41
|
+
...member,
|
42
|
+
}));
|
43
|
+
}
|
package/src/InternalEmitter.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import Emittery from "emittery";
|
2
2
|
import type { TeleBoxRect } from "@netless/telebox-insider";
|
3
3
|
import type { AppInitState, CursorMovePayload } from "./index";
|
4
|
+
import type { Member } from "./Helper";
|
4
5
|
|
5
6
|
export type RemoveSceneParams = {
|
6
7
|
scenePath: string;
|
@@ -29,6 +30,7 @@ export type EmitterEvent = {
|
|
29
30
|
changePageState: undefined;
|
30
31
|
writableChange: boolean;
|
31
32
|
containerSizeRatioUpdate: number;
|
33
|
+
roomMembersChange: Member[];
|
32
34
|
};
|
33
35
|
|
34
36
|
export type EmitterType = Emittery<EmitterEvent>;
|
package/src/constants.ts
CHANGED
package/src/typings.ts
CHANGED
@@ -13,6 +13,7 @@ import type {
|
|
13
13
|
import type { AppContext } from "./App";
|
14
14
|
import type { ReadonlyTeleBox, TeleBoxRect } from "@netless/telebox-insider";
|
15
15
|
import type { PageState } from "./Page";
|
16
|
+
import type { Member } from "./Helper";
|
16
17
|
|
17
18
|
export interface NetlessApp<Attributes = any, MagixEventPayloads = any, AppOptions = any, SetupResult = any> {
|
18
19
|
kind: string;
|
@@ -53,6 +54,7 @@ export type AppEmitterEvent<T = any> = {
|
|
53
54
|
reconnected: void;
|
54
55
|
seek: number;
|
55
56
|
pageStateChange: PageState,
|
57
|
+
roomMembersChange: Member[];
|
56
58
|
};
|
57
59
|
|
58
60
|
export type RegisterEventData = {
|
@@ -79,8 +81,10 @@ export type AppListenerKeys = keyof AppEmitterEvent;
|
|
79
81
|
export type ApplianceIcons = Partial<Record<ApplianceNames, string>>;
|
80
82
|
|
81
83
|
export type { AppContext } from "./App/AppContext";
|
84
|
+
export type { WhiteBoardView } from "./App";
|
82
85
|
export type { ReadonlyTeleBox, TeleBoxRect };
|
83
86
|
export type { SceneState, SceneDefinition, View, AnimationMode, Displayer, Room, Player };
|
84
87
|
export type { Storage, StorageStateChangedEvent, StorageStateChangedListener } from "./App/Storage";
|
85
88
|
export * from "./Page";
|
86
89
|
export * from "./Utils/error";
|
90
|
+
export type { Member } from "./Helper";
|