@netless/app-slide 0.0.27 → 0.0.28
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/SlideController/index.d.ts +10 -3
- package/dist/index.d.ts +4 -2
- package/dist/main.cjs.js +109 -109
- package/dist/main.cjs.js.map +1 -1
- package/dist/main.es.js +1380 -1226
- package/dist/main.es.js.map +1 -1
- package/dist/main.iife.js +108 -108
- package/dist/main.iife.js.map +1 -1
- package/dist/utils/freezer.d.ts +21 -0
- package/package.json +2 -2
- package/src/SlideController/index.ts +75 -11
- package/src/SlideDocsViewer/index.ts +13 -11
- package/src/SlideDocsViewer/style.scss +1 -1
- package/src/index.ts +9 -2
- package/src/utils/freezer.ts +78 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RegisterParams } from "@netless/window-manager";
|
|
2
|
+
export interface FreezableSlide {
|
|
3
|
+
freeze: () => void;
|
|
4
|
+
unfreeze: () => void;
|
|
5
|
+
}
|
|
6
|
+
export declare const FreezerLength = 2;
|
|
7
|
+
export declare const apps: {
|
|
8
|
+
map: Map<string, FreezableSlide>;
|
|
9
|
+
queue: string[];
|
|
10
|
+
validateQueue(): void;
|
|
11
|
+
set(appId: string, slide: FreezableSlide): void;
|
|
12
|
+
delete(appId: string): void;
|
|
13
|
+
focus(appId: string): void;
|
|
14
|
+
};
|
|
15
|
+
export declare type AddHooks = NonNullable<RegisterParams["addHooks"]>;
|
|
16
|
+
/**
|
|
17
|
+
* Put this function in your register code:
|
|
18
|
+
* `WindowManager.register({ addHooks })`
|
|
19
|
+
* So that it will automatically freeze the app when it is not in focus.
|
|
20
|
+
*/
|
|
21
|
+
export declare const addHooks: AddHooks;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netless/app-slide",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.28",
|
|
4
4
|
"main": "dist/main.cjs.js",
|
|
5
5
|
"module": "dist/main.es.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
],
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"@netless/app-shared": "^0.1.1",
|
|
14
|
-
"@netless/slide": "^0.1.
|
|
14
|
+
"@netless/slide": "^0.1.33",
|
|
15
15
|
"@types/color-string": "^1.5.0",
|
|
16
16
|
"color-string": "^1.6.0",
|
|
17
17
|
"side-effect-manager": "^0.1.5",
|
|
@@ -76,6 +76,16 @@ export class SlideController {
|
|
|
76
76
|
this.initialize();
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
public ready = false;
|
|
80
|
+
private resolveReady!: () => void;
|
|
81
|
+
public readonly readyPromise = new Promise<void>(resolve => {
|
|
82
|
+
this.resolveReady = () =>
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
this.ready = true;
|
|
85
|
+
resolve();
|
|
86
|
+
}, 1000);
|
|
87
|
+
});
|
|
88
|
+
|
|
79
89
|
public jumpToPage(page: number) {
|
|
80
90
|
if (this.ready) {
|
|
81
91
|
page = clamp(page, 1, this.pageCount);
|
|
@@ -150,6 +160,8 @@ export class SlideController {
|
|
|
150
160
|
slide.on(SLIDE_EVENTS.renderError, this.onError);
|
|
151
161
|
slide.on(SLIDE_EVENTS.stateChange, this.onStateChange);
|
|
152
162
|
slide.on(SLIDE_EVENTS.syncDispatch, this.onSyncDispatch);
|
|
163
|
+
|
|
164
|
+
slide.on(SLIDE_EVENTS.renderEnd, this.resolveReady);
|
|
153
165
|
}
|
|
154
166
|
|
|
155
167
|
private onSyncDispatch = (event: SyncEvent) => {
|
|
@@ -204,15 +216,14 @@ export class SlideController {
|
|
|
204
216
|
}
|
|
205
217
|
};
|
|
206
218
|
|
|
207
|
-
private resolveReady!: () => void;
|
|
208
|
-
public readonly readyPromise = new Promise<void>(resolve => {
|
|
209
|
-
this.resolveReady = resolve;
|
|
210
|
-
});
|
|
211
|
-
|
|
212
219
|
private pollCount = 0;
|
|
213
220
|
private pollReadyState = () => {
|
|
214
221
|
if (this.ready) {
|
|
215
|
-
this.
|
|
222
|
+
if (this._toFreeze === 1) {
|
|
223
|
+
this.freeze();
|
|
224
|
+
} else if (this._toFreeze === -1) {
|
|
225
|
+
this.unfreeze();
|
|
226
|
+
}
|
|
216
227
|
} else if (this.pollCount < MaxPollCount) {
|
|
217
228
|
this.pollCount++;
|
|
218
229
|
setTimeout(this.pollReadyState, 500);
|
|
@@ -225,12 +236,13 @@ export class SlideController {
|
|
|
225
236
|
}
|
|
226
237
|
};
|
|
227
238
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
239
|
+
// cache `slideCount`, because once the slide is frozen,
|
|
240
|
+
// the `slideCount` will be 0
|
|
241
|
+
private _pageCount = 0;
|
|
232
242
|
public get pageCount() {
|
|
233
|
-
return this.
|
|
243
|
+
if (this._pageCount > 0) return this._pageCount;
|
|
244
|
+
this._pageCount = this.slide.slideCount;
|
|
245
|
+
return this._pageCount;
|
|
234
246
|
}
|
|
235
247
|
|
|
236
248
|
public get page() {
|
|
@@ -283,4 +295,56 @@ export class SlideController {
|
|
|
283
295
|
return Date.now();
|
|
284
296
|
}
|
|
285
297
|
};
|
|
298
|
+
|
|
299
|
+
public isFrozen = false;
|
|
300
|
+
private _toFreeze: -1 | 0 | 1 = 0; // -1: unfreeze, 0: no change, 1: freeze
|
|
301
|
+
private freezePromise: Promise<void> | null = null;
|
|
302
|
+
|
|
303
|
+
private afterFreeze(from: -1 | 1) {
|
|
304
|
+
if (from === 1) {
|
|
305
|
+
this.isFrozen = true;
|
|
306
|
+
this.freezePromise = null;
|
|
307
|
+
if (this._toFreeze === -1) {
|
|
308
|
+
this.unfreeze();
|
|
309
|
+
}
|
|
310
|
+
} else if (from === -1) {
|
|
311
|
+
this.isFrozen = false;
|
|
312
|
+
this.freezePromise = null;
|
|
313
|
+
if (this._toFreeze === 1) {
|
|
314
|
+
this.freeze();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
public freeze = () => {
|
|
320
|
+
if (this.ready) {
|
|
321
|
+
if (this.debug) {
|
|
322
|
+
console.log("[Slide] freeze", this.context.appId);
|
|
323
|
+
}
|
|
324
|
+
if (this.freezePromise) {
|
|
325
|
+
this._toFreeze = 1;
|
|
326
|
+
} else if (!this.isFrozen) {
|
|
327
|
+
this._toFreeze = 0;
|
|
328
|
+
this.freezePromise = this.slide.frozen().then(this.afterFreeze.bind(this, 1));
|
|
329
|
+
}
|
|
330
|
+
} else {
|
|
331
|
+
this._toFreeze = 1;
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
public unfreeze = async () => {
|
|
336
|
+
if (this.ready) {
|
|
337
|
+
if (this.debug) {
|
|
338
|
+
console.log("[Slide] unfreeze", this.context.appId);
|
|
339
|
+
}
|
|
340
|
+
if (this.freezePromise) {
|
|
341
|
+
this._toFreeze = -1;
|
|
342
|
+
} else if (this.isFrozen) {
|
|
343
|
+
this._toFreeze = 0;
|
|
344
|
+
this.freezePromise = this.slide.release().then(this.afterFreeze.bind(this, -1));
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
this._toFreeze = -1;
|
|
348
|
+
}
|
|
349
|
+
};
|
|
286
350
|
}
|
|
@@ -161,17 +161,19 @@ export class SlideDocsViewer {
|
|
|
161
161
|
protected scaleDocsToFit = () => {
|
|
162
162
|
if (this.slideController) {
|
|
163
163
|
const { width, height } = this.slideController.slide;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
this.isViewMounted
|
|
173
|
-
|
|
174
|
-
|
|
164
|
+
if (width && height) {
|
|
165
|
+
this.whiteboardView.moveCameraToContain({
|
|
166
|
+
originX: -width / 2,
|
|
167
|
+
originY: -height / 2,
|
|
168
|
+
width,
|
|
169
|
+
height,
|
|
170
|
+
animationMode: "immediately" as AnimationMode.Immediately,
|
|
171
|
+
});
|
|
172
|
+
if (!this.isViewMounted) {
|
|
173
|
+
this.isViewMounted = true;
|
|
174
|
+
console.log("[Slide] mount whiteboard view");
|
|
175
|
+
this.mountWhiteboard(this.$whiteboardView);
|
|
176
|
+
}
|
|
175
177
|
}
|
|
176
178
|
}
|
|
177
179
|
};
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { NetlessApp } from "@netless/window-manager";
|
|
|
2
2
|
import type { RoomState } from "white-web-sdk";
|
|
3
3
|
import type { MountSlideOptions } from "./SlideDocsViewer";
|
|
4
4
|
import type { Attributes } from "./typings";
|
|
5
|
+
import type { AddHooks, FreezableSlide } from "./utils/freezer";
|
|
5
6
|
|
|
6
7
|
import { SideEffectManager } from "side-effect-manager";
|
|
7
8
|
import { ensureAttributes } from "@netless/app-shared";
|
|
@@ -12,11 +13,12 @@ import {
|
|
|
12
13
|
SlideController,
|
|
13
14
|
} from "./SlideController";
|
|
14
15
|
import { SlideDocsViewer } from "./SlideDocsViewer";
|
|
16
|
+
import { apps, FreezerLength, addHooks } from "./utils/freezer";
|
|
15
17
|
import styles from "./style.scss?inline";
|
|
16
18
|
|
|
17
|
-
export type { Attributes };
|
|
19
|
+
export type { Attributes, AddHooks, FreezableSlide };
|
|
18
20
|
|
|
19
|
-
export { DefaultUrl };
|
|
21
|
+
export { DefaultUrl, apps, FreezerLength, addHooks };
|
|
20
22
|
|
|
21
23
|
const SlideApp: NetlessApp<Attributes> = {
|
|
22
24
|
kind: "Slide",
|
|
@@ -48,6 +50,9 @@ const SlideApp: NetlessApp<Attributes> = {
|
|
|
48
50
|
const room = context.getRoom();
|
|
49
51
|
if (docsViewer && docsViewer.slideController && room && context.getIsWritable()) {
|
|
50
52
|
syncSceneWithSlide(room, context, docsViewer.slideController.slide, baseScenePath);
|
|
53
|
+
if (context.getAppOptions()?.debug || import.meta.env.DEV) {
|
|
54
|
+
console.log("[Slide] page to", page);
|
|
55
|
+
}
|
|
51
56
|
docsViewer.viewer.setPageIndex(page - 1);
|
|
52
57
|
}
|
|
53
58
|
};
|
|
@@ -58,6 +63,7 @@ const SlideApp: NetlessApp<Attributes> = {
|
|
|
58
63
|
...options,
|
|
59
64
|
onPageChanged,
|
|
60
65
|
});
|
|
66
|
+
apps.set(context.appId, slideController);
|
|
61
67
|
if (import.meta.env.DEV) {
|
|
62
68
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
69
|
(window as any).slideController = slideController;
|
|
@@ -95,6 +101,7 @@ const SlideApp: NetlessApp<Attributes> = {
|
|
|
95
101
|
|
|
96
102
|
context.emitter.on("destroy", () => {
|
|
97
103
|
console.log("[Slide]: destroy");
|
|
104
|
+
apps.delete(context.appId);
|
|
98
105
|
sideEffect.flushAll();
|
|
99
106
|
if (docsViewer) {
|
|
100
107
|
docsViewer.destroy();
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { RegisterParams } from "@netless/window-manager";
|
|
2
|
+
|
|
3
|
+
export interface FreezableSlide {
|
|
4
|
+
freeze: () => void;
|
|
5
|
+
unfreeze: () => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const FreezerLength = 2;
|
|
9
|
+
|
|
10
|
+
export const apps = {
|
|
11
|
+
map: new Map<string, FreezableSlide>(),
|
|
12
|
+
queue: [] as string[],
|
|
13
|
+
validateQueue() {
|
|
14
|
+
if (import.meta.env.DEV) {
|
|
15
|
+
console.log("[Slide] freezer: validate", this.queue);
|
|
16
|
+
}
|
|
17
|
+
while (this.queue.length > FreezerLength) {
|
|
18
|
+
const appId = this.queue.pop() as string;
|
|
19
|
+
const slide = this.map.get(appId);
|
|
20
|
+
if (slide) {
|
|
21
|
+
if (import.meta.env.DEV) {
|
|
22
|
+
console.log("[Slide] freezer: validate-freeze", appId, this.queue);
|
|
23
|
+
}
|
|
24
|
+
slide.freeze();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
set(appId: string, slide: FreezableSlide) {
|
|
29
|
+
if (import.meta.env.DEV) {
|
|
30
|
+
console.log("[Slide] freezer: add", appId, this.queue);
|
|
31
|
+
}
|
|
32
|
+
this.map.set(appId, slide);
|
|
33
|
+
if (!this.queue.includes(appId)) {
|
|
34
|
+
this.queue.unshift(appId);
|
|
35
|
+
}
|
|
36
|
+
this.validateQueue();
|
|
37
|
+
},
|
|
38
|
+
delete(appId: string) {
|
|
39
|
+
if (import.meta.env.DEV) {
|
|
40
|
+
console.log("[Slide] freezer: delete", appId, this.queue);
|
|
41
|
+
}
|
|
42
|
+
this.map.delete(appId);
|
|
43
|
+
this.queue = this.queue.filter(id => id !== appId);
|
|
44
|
+
},
|
|
45
|
+
focus(appId: string) {
|
|
46
|
+
const slide = this.map.get(appId);
|
|
47
|
+
const index = this.queue.indexOf(appId);
|
|
48
|
+
if (index > -1) {
|
|
49
|
+
this.queue.splice(index, 1);
|
|
50
|
+
}
|
|
51
|
+
this.queue.unshift(appId);
|
|
52
|
+
this.validateQueue();
|
|
53
|
+
if (import.meta.env.DEV) {
|
|
54
|
+
console.log("[Slide] freezer: focus", appId, this.queue);
|
|
55
|
+
}
|
|
56
|
+
if (slide) {
|
|
57
|
+
slide.unfreeze();
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (import.meta.env.DEV) {
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
(window as any).freezer = apps;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type AddHooks = NonNullable<RegisterParams["addHooks"]>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Put this function in your register code:
|
|
71
|
+
* `WindowManager.register({ addHooks })`
|
|
72
|
+
* So that it will automatically freeze the app when it is not in focus.
|
|
73
|
+
*/
|
|
74
|
+
export const addHooks: AddHooks = emitter => {
|
|
75
|
+
emitter.on("focus", ({ appId }) => {
|
|
76
|
+
apps.focus(appId);
|
|
77
|
+
});
|
|
78
|
+
};
|