@netless/fastboard-core 0.3.2-canary.5 → 0.3.3
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/LICENSE.txt +21 -21
- package/README.md +9 -9
- package/dist/index.d.ts +366 -317
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -4
- package/src/behaviors/index.ts +62 -52
- package/src/impl/FastboardApp.ts +602 -555
- package/src/impl/FastboardPlayer.ts +233 -232
- package/src/impl/index.ts +3 -3
- package/src/index.ts +2 -2
- package/src/internal.ts +14 -14
- package/src/utils/index.ts +4 -4
- package/src/utils/misc.ts +49 -49
- package/src/utils/store.ts +87 -87
- package/src/utils/uid.ts +12 -12
- package/src/utils/warn.ts +11 -11
package/src/impl/FastboardApp.ts
CHANGED
|
@@ -1,555 +1,602 @@
|
|
|
1
|
-
import type { AddPageParams, PublicEvent, MountParams } from "@netless/window-manager";
|
|
2
|
-
import type {
|
|
3
|
-
AnimationMode,
|
|
4
|
-
ApplianceNames,
|
|
5
|
-
Camera,
|
|
6
|
-
Color,
|
|
7
|
-
ConversionResponse,
|
|
8
|
-
HotKey,
|
|
9
|
-
HotKeys,
|
|
10
|
-
JoinRoomParams,
|
|
11
|
-
MemberState,
|
|
12
|
-
Rectangle,
|
|
13
|
-
Room,
|
|
14
|
-
RoomPhase as RoomPhaseEnum,
|
|
15
|
-
RoomCallbacks,
|
|
16
|
-
RoomState,
|
|
17
|
-
SceneDefinition,
|
|
18
|
-
ShapeType,
|
|
19
|
-
ViewCallbacks,
|
|
20
|
-
WhiteWebSdkConfiguration,
|
|
21
|
-
} from "white-web-sdk";
|
|
22
|
-
|
|
23
|
-
import { DefaultHotKeys, WhiteWebSdk, contentModeScale } from "white-web-sdk";
|
|
24
|
-
import { BuiltinApps, WindowManager } from "@netless/window-manager";
|
|
25
|
-
import {
|
|
26
|
-
getImageSize,
|
|
27
|
-
genUID,
|
|
28
|
-
convertedFileToScene,
|
|
29
|
-
makeSlideParams,
|
|
30
|
-
readable,
|
|
31
|
-
writable,
|
|
32
|
-
warn,
|
|
33
|
-
} from "../utils";
|
|
34
|
-
import { ensure_window_manager, transform_app_status } from "../internal";
|
|
35
|
-
|
|
36
|
-
class FastboardAppBase {
|
|
37
|
-
public constructor(
|
|
38
|
-
readonly sdk: WhiteWebSdk,
|
|
39
|
-
readonly room: Room,
|
|
40
|
-
readonly manager: WindowManager,
|
|
41
|
-
readonly hotKeys: Partial<HotKeys>
|
|
42
|
-
) {}
|
|
43
|
-
|
|
44
|
-
protected _destroyed = false;
|
|
45
|
-
protected _assertNotDestroyed() {
|
|
46
|
-
if (this._destroyed) {
|
|
47
|
-
throw new Error("FastboardApp has been destroyed");
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
protected _addRoomListener<K extends keyof RoomCallbacks>(name: K, listener: RoomCallbacks[K]) {
|
|
52
|
-
this._assertNotDestroyed();
|
|
53
|
-
this.room.callbacks.on(name, listener);
|
|
54
|
-
return () => this.room.callbacks.off(name, listener);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
protected _addManagerListener<K extends keyof PublicEvent>(
|
|
58
|
-
name: K,
|
|
59
|
-
listener: (value: PublicEvent[K]) => void
|
|
60
|
-
) {
|
|
61
|
-
this._assertNotDestroyed();
|
|
62
|
-
this.manager.emitter.on(name, listener);
|
|
63
|
-
return () => this.manager.emitter.off(name, listener);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
protected _addMainViewListener<K extends keyof ViewCallbacks>(name: K, listener: ViewCallbacks[K]) {
|
|
67
|
-
this._assertNotDestroyed();
|
|
68
|
-
this.manager.mainView.callbacks.on(name, listener);
|
|
69
|
-
return () => this.manager.mainView.callbacks.off(name, listener);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
readonly scenePath: string;
|
|
120
|
-
|
|
121
|
-
readonly
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
export
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
*
|
|
159
|
-
*/
|
|
160
|
-
|
|
161
|
-
this.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
*
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
this.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
this.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
*
|
|
204
|
-
*/
|
|
205
|
-
readonly
|
|
206
|
-
this._addManagerListener("
|
|
207
|
-
set(this.manager.
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
*
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
this.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
*
|
|
279
|
-
*/
|
|
280
|
-
|
|
281
|
-
this._assertNotDestroyed();
|
|
282
|
-
this.manager.
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
*
|
|
287
|
-
*/
|
|
288
|
-
|
|
289
|
-
this._assertNotDestroyed();
|
|
290
|
-
this.manager.
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
*
|
|
295
|
-
*/
|
|
296
|
-
|
|
297
|
-
this._assertNotDestroyed();
|
|
298
|
-
this.manager.
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
*
|
|
303
|
-
*/
|
|
304
|
-
|
|
305
|
-
this._assertNotDestroyed();
|
|
306
|
-
this.manager.
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
this._assertNotDestroyed();
|
|
314
|
-
this.manager.
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
this.
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
this.manager.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
this.manager.
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
this._assertNotDestroyed();
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
*
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
1
|
+
import type { AddPageParams, PublicEvent, MountParams } from "@netless/window-manager";
|
|
2
|
+
import type {
|
|
3
|
+
AnimationMode,
|
|
4
|
+
ApplianceNames,
|
|
5
|
+
Camera,
|
|
6
|
+
Color,
|
|
7
|
+
ConversionResponse,
|
|
8
|
+
HotKey,
|
|
9
|
+
HotKeys,
|
|
10
|
+
JoinRoomParams,
|
|
11
|
+
MemberState,
|
|
12
|
+
Rectangle,
|
|
13
|
+
Room,
|
|
14
|
+
RoomPhase as RoomPhaseEnum,
|
|
15
|
+
RoomCallbacks,
|
|
16
|
+
RoomState,
|
|
17
|
+
SceneDefinition,
|
|
18
|
+
ShapeType,
|
|
19
|
+
ViewCallbacks,
|
|
20
|
+
WhiteWebSdkConfiguration,
|
|
21
|
+
} from "white-web-sdk";
|
|
22
|
+
|
|
23
|
+
import { DefaultHotKeys, WhiteWebSdk, contentModeScale } from "white-web-sdk";
|
|
24
|
+
import { BuiltinApps, WindowManager } from "@netless/window-manager";
|
|
25
|
+
import {
|
|
26
|
+
getImageSize,
|
|
27
|
+
genUID,
|
|
28
|
+
convertedFileToScene,
|
|
29
|
+
makeSlideParams,
|
|
30
|
+
readable,
|
|
31
|
+
writable,
|
|
32
|
+
warn,
|
|
33
|
+
} from "../utils";
|
|
34
|
+
import { ensure_window_manager, transform_app_status } from "../internal";
|
|
35
|
+
|
|
36
|
+
class FastboardAppBase {
|
|
37
|
+
public constructor(
|
|
38
|
+
readonly sdk: WhiteWebSdk,
|
|
39
|
+
readonly room: Room,
|
|
40
|
+
readonly manager: WindowManager,
|
|
41
|
+
readonly hotKeys: Partial<HotKeys>
|
|
42
|
+
) {}
|
|
43
|
+
|
|
44
|
+
protected _destroyed = false;
|
|
45
|
+
protected _assertNotDestroyed() {
|
|
46
|
+
if (this._destroyed) {
|
|
47
|
+
throw new Error("FastboardApp has been destroyed");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
protected _addRoomListener<K extends keyof RoomCallbacks>(name: K, listener: RoomCallbacks[K]) {
|
|
52
|
+
this._assertNotDestroyed();
|
|
53
|
+
this.room.callbacks.on(name, listener);
|
|
54
|
+
return () => this.room.callbacks.off(name, listener);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
protected _addManagerListener<K extends keyof PublicEvent>(
|
|
58
|
+
name: K,
|
|
59
|
+
listener: (value: PublicEvent[K]) => void
|
|
60
|
+
) {
|
|
61
|
+
this._assertNotDestroyed();
|
|
62
|
+
this.manager.emitter.on(name, listener);
|
|
63
|
+
return () => this.manager.emitter.off(name, listener);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
protected _addMainViewListener<K extends keyof ViewCallbacks>(name: K, listener: ViewCallbacks[K]) {
|
|
67
|
+
this._assertNotDestroyed();
|
|
68
|
+
this.manager.mainView.callbacks.on(name, listener);
|
|
69
|
+
return () => this.manager.mainView.callbacks.off(name, listener);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Destroy fastboard (disconnect from the whiteboard room).
|
|
74
|
+
*/
|
|
75
|
+
public destroy() {
|
|
76
|
+
this._destroyed = true;
|
|
77
|
+
this.manager.destroy();
|
|
78
|
+
return this.room.disconnect();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
type RoomPhase = `${RoomPhaseEnum}`;
|
|
83
|
+
|
|
84
|
+
export type {
|
|
85
|
+
AddPageParams,
|
|
86
|
+
AnimationMode,
|
|
87
|
+
ApplianceNames,
|
|
88
|
+
Camera,
|
|
89
|
+
Color,
|
|
90
|
+
ConversionResponse,
|
|
91
|
+
HotKey,
|
|
92
|
+
HotKeys,
|
|
93
|
+
JoinRoomParams,
|
|
94
|
+
MemberState,
|
|
95
|
+
MountParams,
|
|
96
|
+
PublicEvent,
|
|
97
|
+
Rectangle,
|
|
98
|
+
Room,
|
|
99
|
+
RoomPhase,
|
|
100
|
+
RoomCallbacks,
|
|
101
|
+
RoomState,
|
|
102
|
+
SceneDefinition,
|
|
103
|
+
ShapeType,
|
|
104
|
+
ViewCallbacks,
|
|
105
|
+
WhiteWebSdk,
|
|
106
|
+
WhiteWebSdkConfiguration,
|
|
107
|
+
WindowManager,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/** pencil, eraser, rectangle... */
|
|
111
|
+
export type Appliance = `${ApplianceNames}`;
|
|
112
|
+
/** triangle, star... */
|
|
113
|
+
export type Shape = `${ShapeType}`;
|
|
114
|
+
|
|
115
|
+
/** Params for static docs, they are rendered as many images. */
|
|
116
|
+
export interface InsertDocsStatic {
|
|
117
|
+
readonly fileType: "pdf";
|
|
118
|
+
/** Unique string for binding whiteboard view to the doc. Must start with `/`. */
|
|
119
|
+
readonly scenePath: string;
|
|
120
|
+
/** @example [{ name: '1', ppt: { src: 'url/to/ppt/1.png' } }] */
|
|
121
|
+
readonly scenes: SceneDefinition[];
|
|
122
|
+
/** Window title. */
|
|
123
|
+
readonly title?: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Params for slides, they are rendered in @netless/app-slide with animations. */
|
|
127
|
+
export interface InsertDocsDynamic {
|
|
128
|
+
readonly fileType: "pptx";
|
|
129
|
+
/** Unique string for binding whiteboard view to the doc. Must start with `/`. */
|
|
130
|
+
readonly scenePath: string;
|
|
131
|
+
/** Conversion task id, see https://developer.netless.link/server-en/home/server-conversion#get-query-task-conversion-progress. */
|
|
132
|
+
readonly taskId: string;
|
|
133
|
+
/** Window title. */
|
|
134
|
+
readonly title?: string;
|
|
135
|
+
/** Where the slide resource placed. @default `https://convertcdn.netless.link/dynamicConvert` */
|
|
136
|
+
readonly url?: string;
|
|
137
|
+
/** @example [{ name: '1' }, { name: '2' }, { name: '3' }] */
|
|
138
|
+
readonly scenes?: SceneDefinition[];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export type InsertDocsParams = InsertDocsStatic | InsertDocsDynamic;
|
|
142
|
+
|
|
143
|
+
export type SetMemberStateFn = (partialMemberState: Partial<MemberState>) => void;
|
|
144
|
+
|
|
145
|
+
export type RoomStateChanged = (diff: Partial<RoomState>) => void;
|
|
146
|
+
|
|
147
|
+
/** App download progress. */
|
|
148
|
+
export interface AppsStatus {
|
|
149
|
+
[kind: string]: {
|
|
150
|
+
status: "idle" | "loading" | "failed";
|
|
151
|
+
/** Exist if status is `failed`. */
|
|
152
|
+
reason?: string;
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export class FastboardApp extends FastboardAppBase {
|
|
157
|
+
/**
|
|
158
|
+
* Render this app to some DOM.
|
|
159
|
+
*/
|
|
160
|
+
bindContainer(container: HTMLElement) {
|
|
161
|
+
this._assertNotDestroyed();
|
|
162
|
+
this.manager.bindContainer(container);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Move window-manager's collector to some place.
|
|
167
|
+
*/
|
|
168
|
+
bindCollector(container: HTMLElement) {
|
|
169
|
+
this._assertNotDestroyed();
|
|
170
|
+
this.manager.bindCollectorContainer(container);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Is current room writable?
|
|
175
|
+
*/
|
|
176
|
+
readonly writable = writable(
|
|
177
|
+
this.room.isWritable,
|
|
178
|
+
set => {
|
|
179
|
+
this._addRoomListener("onEnableWriteNowChanged", () => set(this.room.isWritable));
|
|
180
|
+
set(this.room.isWritable);
|
|
181
|
+
},
|
|
182
|
+
this.room.setWritable.bind(this.room)
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Is current room online?
|
|
187
|
+
*/
|
|
188
|
+
readonly phase = readable<RoomPhase>(this.room.phase, set => {
|
|
189
|
+
this._addRoomListener("onPhaseChanged", set);
|
|
190
|
+
set(this.room.phase);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Current window-manager's windows' state (is it maximized?).
|
|
195
|
+
*/
|
|
196
|
+
readonly boxState = readable(this.manager.boxState, set => {
|
|
197
|
+
this._addManagerListener("boxStateChange", set);
|
|
198
|
+
set(this.manager.boxState);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Current window-manager's focused app's id.
|
|
203
|
+
* @example "HelloWorld-1A2b3C4d"
|
|
204
|
+
*/
|
|
205
|
+
readonly focusedApp = readable(this.manager.focused, set => {
|
|
206
|
+
this._addManagerListener("focusedChange", set);
|
|
207
|
+
set(this.manager.focused);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* How many times can I call `app.redo()`?
|
|
212
|
+
*/
|
|
213
|
+
readonly canRedoSteps = readable(this.manager.canRedoSteps, set => {
|
|
214
|
+
this._addManagerListener("canRedoStepsChange", set);
|
|
215
|
+
set(this.manager.canRedoSteps);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* How many times can I call `app.undo()`?
|
|
220
|
+
*/
|
|
221
|
+
readonly canUndoSteps = readable(this.manager.canUndoSteps, set => {
|
|
222
|
+
this._addManagerListener("canUndoStepsChange", set);
|
|
223
|
+
set(this.manager.canUndoSteps);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Current camera information of main view.
|
|
228
|
+
*
|
|
229
|
+
* Change the camera position by `app.moveCamera()`.
|
|
230
|
+
*/
|
|
231
|
+
readonly camera = readable(this.manager.camera, set => {
|
|
232
|
+
this._addMainViewListener("onCameraUpdated", set);
|
|
233
|
+
set(this.manager.camera);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Current tool's info, like "is using pencil?", "what color?".
|
|
238
|
+
*
|
|
239
|
+
* Change the tool by `app.setAppliance()`.
|
|
240
|
+
*/
|
|
241
|
+
readonly memberState = readable(this.room.state.memberState, set => {
|
|
242
|
+
this._addRoomListener("onRoomStateChanged", ({ memberState: m }) => m && set(m));
|
|
243
|
+
set(this.room.state.memberState);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* 0..n-1, current index of main view scenes.
|
|
248
|
+
*/
|
|
249
|
+
readonly sceneIndex = writable(
|
|
250
|
+
this.manager.mainViewSceneIndex,
|
|
251
|
+
set => {
|
|
252
|
+
this._addManagerListener("mainViewSceneIndexChange", set);
|
|
253
|
+
set(this.manager.mainViewSceneIndex);
|
|
254
|
+
},
|
|
255
|
+
this.manager.setMainViewSceneIndex.bind(this.manager)
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* How many pages are in the main view?
|
|
260
|
+
*/
|
|
261
|
+
readonly sceneLength = readable(this.manager.mainViewScenesLength, set => {
|
|
262
|
+
this._addManagerListener("mainViewScenesLengthChange", set);
|
|
263
|
+
set(this.manager.mainViewScenesLength);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
private _appsStatus: AppsStatus = {};
|
|
267
|
+
/**
|
|
268
|
+
* Apps status.
|
|
269
|
+
*/
|
|
270
|
+
readonly appsStatus = readable<AppsStatus>({}, set =>
|
|
271
|
+
this._addManagerListener("loadApp", ({ kind, status, reason }) => {
|
|
272
|
+
this._appsStatus[kind] = { status: transform_app_status(status), reason };
|
|
273
|
+
set(this._appsStatus);
|
|
274
|
+
})
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Undo a step on main view.
|
|
279
|
+
*/
|
|
280
|
+
undo() {
|
|
281
|
+
this._assertNotDestroyed();
|
|
282
|
+
this.manager.undo();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Redo a step on main view.
|
|
287
|
+
*/
|
|
288
|
+
redo() {
|
|
289
|
+
this._assertNotDestroyed();
|
|
290
|
+
this.manager.redo();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Move current main view's camera position.
|
|
295
|
+
*/
|
|
296
|
+
moveCamera(camera: Partial<Camera> & { animationMode?: AnimationMode | undefined }) {
|
|
297
|
+
this._assertNotDestroyed();
|
|
298
|
+
this.manager.moveCamera(camera);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Move current main view's camera to include a rectangle.
|
|
303
|
+
*/
|
|
304
|
+
moveCameraToContain(rectangle: Rectangle & { animationMode?: AnimationMode }) {
|
|
305
|
+
this._assertNotDestroyed();
|
|
306
|
+
this.manager.moveCameraToContain(rectangle);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Delete all things on the main view.
|
|
311
|
+
*/
|
|
312
|
+
cleanCurrentScene() {
|
|
313
|
+
this._assertNotDestroyed();
|
|
314
|
+
this.manager.cleanCurrentScene();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Set current tool, like "pencil".
|
|
319
|
+
*/
|
|
320
|
+
setAppliance(appliance: ApplianceNames | Appliance, shape?: ShapeType | Shape) {
|
|
321
|
+
this._assertNotDestroyed();
|
|
322
|
+
this.manager.mainView.setMemberState({
|
|
323
|
+
currentApplianceName: appliance as ApplianceNames,
|
|
324
|
+
shapeType: shape as ShapeType,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Set pencil and shape's thickness.
|
|
330
|
+
*/
|
|
331
|
+
setStrokeWidth(strokeWidth: number) {
|
|
332
|
+
this._assertNotDestroyed();
|
|
333
|
+
this.manager.mainView.setMemberState({ strokeWidth });
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Set pencil and shape's color.
|
|
338
|
+
*/
|
|
339
|
+
setStrokeColor(strokeColor: Color) {
|
|
340
|
+
this._assertNotDestroyed();
|
|
341
|
+
this.manager.mainView.setMemberState({ strokeColor });
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Set text size. Default is 16.
|
|
346
|
+
*/
|
|
347
|
+
setTextSize(textSize: number) {
|
|
348
|
+
this._assertNotDestroyed();
|
|
349
|
+
this.manager.mainView.setMemberState({ textSize });
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Set text color.
|
|
354
|
+
*
|
|
355
|
+
* @example
|
|
356
|
+
* setTextColor([0x66, 0xcc, 0xff])
|
|
357
|
+
*/
|
|
358
|
+
setTextColor(textColor: Color) {
|
|
359
|
+
this._assertNotDestroyed();
|
|
360
|
+
this.manager.mainView.setMemberState({ textColor });
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Goto previous page (the main whiteboard view).
|
|
365
|
+
*/
|
|
366
|
+
prevPage() {
|
|
367
|
+
this._assertNotDestroyed();
|
|
368
|
+
return this.manager.prevPage();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Goto next page (the main whiteboard view).
|
|
373
|
+
*/
|
|
374
|
+
nextPage() {
|
|
375
|
+
this._assertNotDestroyed();
|
|
376
|
+
return this.manager.nextPage();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Add one page to the main whiteboard view.
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* addPage({ after: true }) // add one page right after current one.
|
|
384
|
+
* nextPage() // then, goto that page.
|
|
385
|
+
*/
|
|
386
|
+
addPage(params?: AddPageParams) {
|
|
387
|
+
this._assertNotDestroyed();
|
|
388
|
+
return this.manager.addPage(params);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Insert an image to the main view.
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* insertImage("https://i.imgur.com/CzXTtJV.jpg")
|
|
396
|
+
*/
|
|
397
|
+
async insertImage(url: string) {
|
|
398
|
+
this._assertNotDestroyed();
|
|
399
|
+
await this.manager.switchMainViewToWriter();
|
|
400
|
+
|
|
401
|
+
const { divElement } = this.manager.mainView;
|
|
402
|
+
const containerSize = {
|
|
403
|
+
width: divElement?.scrollWidth || window.innerWidth,
|
|
404
|
+
height: divElement?.scrollHeight || window.innerHeight,
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// 1. shrink the image a little to fit container **width**
|
|
408
|
+
const maxWidth = containerSize.width * 0.8;
|
|
409
|
+
let { width, height } = await getImageSize(url, containerSize);
|
|
410
|
+
const scale = Math.min(maxWidth / width, 1);
|
|
411
|
+
const uuid = genUID();
|
|
412
|
+
const { centerX, centerY } = this.manager.camera;
|
|
413
|
+
width *= scale;
|
|
414
|
+
height *= scale;
|
|
415
|
+
this.manager.mainView.insertImage({ uuid, centerX, centerY, width, height, locked: false });
|
|
416
|
+
this.manager.mainView.completeImageUpload(uuid, url);
|
|
417
|
+
|
|
418
|
+
// 2. move camera to fit image **height**
|
|
419
|
+
width /= 0.8;
|
|
420
|
+
height /= 0.8;
|
|
421
|
+
const originX = centerX - width / 2;
|
|
422
|
+
const originY = centerY - height / 2;
|
|
423
|
+
this.manager.moveCameraToContain({ originX, originY, width, height });
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Insert PDF/PPTX from conversion result.
|
|
428
|
+
* @param status https://developer.netless.link/server-en/home/server-conversion#get-query-task-conversion-progress
|
|
429
|
+
*/
|
|
430
|
+
insertDocs(filename: string, status: ConversionResponse): Promise<string | undefined>;
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Manual way.
|
|
434
|
+
* @example
|
|
435
|
+
* app.insertDocs({
|
|
436
|
+
* fileType: 'pptx',
|
|
437
|
+
* scenePath: `/pptx/${conversion.taskId}`,
|
|
438
|
+
* taskId: conversion.taskId,
|
|
439
|
+
* title: 'Title',
|
|
440
|
+
* })
|
|
441
|
+
*/
|
|
442
|
+
insertDocs(params: InsertDocsParams): Promise<string | undefined>;
|
|
443
|
+
|
|
444
|
+
insertDocs(arg1: string | InsertDocsParams, arg2?: ConversionResponse) {
|
|
445
|
+
this._assertNotDestroyed();
|
|
446
|
+
if (typeof arg1 === "object" && "fileType" in arg1) {
|
|
447
|
+
return this._insertDocsImpl(arg1);
|
|
448
|
+
} else if (arg2 && arg2.status !== "Finished") {
|
|
449
|
+
throw new Error("FastboardApp cannot insert a converting doc.");
|
|
450
|
+
} else if (arg2 && arg2.progress) {
|
|
451
|
+
const title = arg1;
|
|
452
|
+
const scenePath = `/${arg2.uuid}/${genUID()}`;
|
|
453
|
+
const scenes1 = arg2.progress.convertedFileList.map(convertedFileToScene);
|
|
454
|
+
const { scenes, taskId, url } = makeSlideParams(scenes1);
|
|
455
|
+
if (taskId && url) {
|
|
456
|
+
return this._insertDocsImpl({ fileType: "pptx", scenePath, scenes, title, taskId, url });
|
|
457
|
+
} else {
|
|
458
|
+
return this._insertDocsImpl({ fileType: "pdf", scenePath, scenes: scenes1, title });
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
private _insertDocsImpl({ fileType, scenePath, title, scenes, ...attributes }: InsertDocsParams) {
|
|
464
|
+
this._assertNotDestroyed();
|
|
465
|
+
switch (fileType) {
|
|
466
|
+
case "pdf":
|
|
467
|
+
return this.manager.addApp({
|
|
468
|
+
kind: "DocsViewer",
|
|
469
|
+
options: { scenePath, title, scenes },
|
|
470
|
+
});
|
|
471
|
+
case "pptx":
|
|
472
|
+
if (scenes && scenes[0].ppt) {
|
|
473
|
+
warn("no-ppt-in-scenes");
|
|
474
|
+
}
|
|
475
|
+
return this.manager.addApp({
|
|
476
|
+
kind: "Slide",
|
|
477
|
+
options: { scenePath, title, scenes },
|
|
478
|
+
attributes,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* Insert the Media Player app.
|
|
485
|
+
*/
|
|
486
|
+
insertMedia(title: string, src: string) {
|
|
487
|
+
this._assertNotDestroyed();
|
|
488
|
+
return this.manager.addApp({
|
|
489
|
+
kind: BuiltinApps.MediaPlayer,
|
|
490
|
+
options: { title },
|
|
491
|
+
attributes: { src },
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Insert the Monaco Code Editor app.
|
|
497
|
+
*/
|
|
498
|
+
insertCodeEditor() {
|
|
499
|
+
this._assertNotDestroyed();
|
|
500
|
+
return this.manager.addApp({
|
|
501
|
+
kind: "Monaco",
|
|
502
|
+
options: { title: "Code Editor" },
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Insert the Countdown app.
|
|
508
|
+
*/
|
|
509
|
+
insertCountdown() {
|
|
510
|
+
this._assertNotDestroyed();
|
|
511
|
+
return this.manager.addApp({
|
|
512
|
+
kind: "Countdown",
|
|
513
|
+
options: { title: "Countdown" },
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Insert the GeoGebra app.
|
|
519
|
+
*/
|
|
520
|
+
insertGeoGebra() {
|
|
521
|
+
this._assertNotDestroyed();
|
|
522
|
+
return this.manager.addApp({
|
|
523
|
+
kind: "GeoGebra",
|
|
524
|
+
options: { title: "GeoGebra" },
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
export interface FastboardOptions {
|
|
530
|
+
sdkConfig: Omit<WhiteWebSdkConfiguration, "useMobXState"> & {
|
|
531
|
+
region: NonNullable<WhiteWebSdkConfiguration["region"]>;
|
|
532
|
+
};
|
|
533
|
+
joinRoom: Omit<JoinRoomParams, "useMultiViews" | "disableNewPencil" | "disableMagixEventDispatchLimit"> & {
|
|
534
|
+
callbacks?: Partial<RoomCallbacks>;
|
|
535
|
+
};
|
|
536
|
+
managerConfig?: Omit<MountParams, "room">;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Create a FastboardApp instance.
|
|
541
|
+
* @example
|
|
542
|
+
* let app = await createFastboard({
|
|
543
|
+
* sdkConfig: {
|
|
544
|
+
* appIdentifier: import.meta.env.VITE_APPID,
|
|
545
|
+
* region: 'cn-hz',
|
|
546
|
+
* },
|
|
547
|
+
* joinRoom: {
|
|
548
|
+
* uid: unique_id,
|
|
549
|
+
* uuid: import.meta.env.VITE_ROOM_UUID,
|
|
550
|
+
* roomToken: import.meta.env.VITE_ROOM_TOKEN,
|
|
551
|
+
* },
|
|
552
|
+
* })
|
|
553
|
+
*/
|
|
554
|
+
export async function createFastboard({
|
|
555
|
+
sdkConfig,
|
|
556
|
+
joinRoom: { callbacks, ...joinRoomParams },
|
|
557
|
+
managerConfig,
|
|
558
|
+
}: FastboardOptions) {
|
|
559
|
+
const sdk = new WhiteWebSdk({
|
|
560
|
+
...sdkConfig,
|
|
561
|
+
useMobXState: true,
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
const hotKeys: Partial<HotKeys> = {
|
|
565
|
+
...DefaultHotKeys,
|
|
566
|
+
changeToSelector: "s",
|
|
567
|
+
changeToLaserPointer: "z",
|
|
568
|
+
changeToPencil: "p",
|
|
569
|
+
changeToRectangle: "r",
|
|
570
|
+
changeToEllipse: "c",
|
|
571
|
+
changeToEraser: "e",
|
|
572
|
+
changeToText: "t",
|
|
573
|
+
changeToStraight: "l",
|
|
574
|
+
changeToArrow: "a",
|
|
575
|
+
changeToHand: "h",
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
const room = await sdk.joinRoom(
|
|
579
|
+
{
|
|
580
|
+
floatBar: true,
|
|
581
|
+
hotKeys,
|
|
582
|
+
...ensure_window_manager(joinRoomParams),
|
|
583
|
+
useMultiViews: true,
|
|
584
|
+
disableNewPencil: false,
|
|
585
|
+
disableMagixEventDispatchLimit: true,
|
|
586
|
+
},
|
|
587
|
+
callbacks
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
const manager = await WindowManager.mount({
|
|
591
|
+
cursor: true,
|
|
592
|
+
...managerConfig,
|
|
593
|
+
room,
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
manager.mainView.setCameraBound({
|
|
597
|
+
minContentMode: contentModeScale(0.3),
|
|
598
|
+
maxContentMode: contentModeScale(3),
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
return new FastboardApp(sdk, room, manager, hotKeys);
|
|
602
|
+
}
|