@audiowalk/sdk 1.5.0 → 1.5.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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/player/media-controls.d.ts +9 -0
- package/dist/player/media-controls.d.ts.map +1 -0
- package/dist/player/media-controls.js +54 -0
- package/dist/player/player-controller.d.ts +22 -8
- package/dist/player/player-controller.d.ts.map +1 -1
- package/dist/player/player-controller.js +78 -60
- package/dist/story/story-controller.d.ts.map +1 -1
- package/dist/story/story-controller.js +6 -4
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PlayerController } from "./player-controller";
|
|
2
|
+
export declare class MediaControlsController {
|
|
3
|
+
private playerDetachEvent;
|
|
4
|
+
setMetadata(metadata: MediaMetadataInit): void;
|
|
5
|
+
attachPlayer(player: PlayerController): void;
|
|
6
|
+
detachPlayer(): void;
|
|
7
|
+
clear(): void;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=media-controls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-controls.d.ts","sourceRoot":"","sources":["../../src/player/media-controls.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,qBAAa,uBAAuB;IAClC,OAAO,CAAC,iBAAiB,CAAuB;IAEhD,WAAW,CAAC,QAAQ,EAAE,iBAAiB;IAMvC,YAAY,CAAC,MAAM,EAAE,gBAAgB;IAoCrC,YAAY;IASZ,KAAK;CAMN"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { combineLatest, Subject, takeUntil } from "rxjs";
|
|
2
|
+
export class MediaControlsController {
|
|
3
|
+
playerDetachEvent = new Subject();
|
|
4
|
+
setMetadata(metadata) {
|
|
5
|
+
navigator.mediaSession.metadata = new MediaMetadata(metadata);
|
|
6
|
+
navigator.mediaSession.playbackState = "paused";
|
|
7
|
+
navigator.mediaSession.setActionHandler("play", () => console.log("play"));
|
|
8
|
+
}
|
|
9
|
+
attachPlayer(player) {
|
|
10
|
+
this.detachPlayer();
|
|
11
|
+
navigator.mediaSession.setActionHandler("play", () => player.play());
|
|
12
|
+
navigator.mediaSession.setActionHandler("pause", () => player.pause());
|
|
13
|
+
navigator.mediaSession.setActionHandler("seekbackward", () => player.back());
|
|
14
|
+
navigator.mediaSession.setActionHandler("seekforward", () => player.forward());
|
|
15
|
+
navigator.mediaSession.setActionHandler("previoustrack", () => player.back());
|
|
16
|
+
navigator.mediaSession.setActionHandler("nexttrack", () => player.forward());
|
|
17
|
+
navigator.mediaSession.setActionHandler("seekto", (details) => {
|
|
18
|
+
// The fastSeek dictionary member will be true if the seek action is being called
|
|
19
|
+
// multiple times as part of a sequence and this is not the last call in that sequence.
|
|
20
|
+
if (details.fastSeek !== true && details.seekTime !== undefined)
|
|
21
|
+
player.seekTo(details.seekTime);
|
|
22
|
+
});
|
|
23
|
+
player.status.pipe(takeUntil(this.playerDetachEvent)).subscribe((status) => {
|
|
24
|
+
switch (status) {
|
|
25
|
+
case "playing":
|
|
26
|
+
navigator.mediaSession.playbackState = "playing";
|
|
27
|
+
break;
|
|
28
|
+
case "paused":
|
|
29
|
+
navigator.mediaSession.playbackState = "paused";
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
combineLatest([player.currentTime, player.totalTime])
|
|
34
|
+
.pipe(takeUntil(this.playerDetachEvent))
|
|
35
|
+
.subscribe(([currentTime, totalTime]) => {
|
|
36
|
+
navigator.mediaSession.setPositionState({
|
|
37
|
+
duration: Number.isNaN(totalTime) ? 0 : totalTime,
|
|
38
|
+
position: currentTime,
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
detachPlayer() {
|
|
43
|
+
this.playerDetachEvent.next();
|
|
44
|
+
navigator.mediaSession.setActionHandler("play", null);
|
|
45
|
+
navigator.mediaSession.setActionHandler("pause", null);
|
|
46
|
+
navigator.mediaSession.setActionHandler("previoustrack", null);
|
|
47
|
+
navigator.mediaSession.setActionHandler("nexttrack", null);
|
|
48
|
+
}
|
|
49
|
+
clear() {
|
|
50
|
+
this.detachPlayer();
|
|
51
|
+
navigator.mediaSession.playbackState = "none";
|
|
52
|
+
navigator.mediaSession.metadata = null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { BehaviorSubject, Subject } from "rxjs";
|
|
2
2
|
export interface PlayerControllerOptions {
|
|
3
|
-
playOnInit?: boolean;
|
|
4
3
|
autoSave?: boolean;
|
|
4
|
+
audioElement?: HTMLAudioElement;
|
|
5
|
+
loop?: boolean;
|
|
6
|
+
fadeIn?: boolean;
|
|
7
|
+
fadeOut?: boolean;
|
|
8
|
+
fadeInterval?: number;
|
|
5
9
|
}
|
|
6
10
|
export declare enum PlayerStatus {
|
|
7
11
|
"playing" = "playing",
|
|
@@ -9,8 +13,6 @@ export declare enum PlayerStatus {
|
|
|
9
13
|
"ended" = "ended"
|
|
10
14
|
}
|
|
11
15
|
export declare class PlayerController {
|
|
12
|
-
private readonly playerElement;
|
|
13
|
-
private options;
|
|
14
16
|
readonly onPlay: Subject<void>;
|
|
15
17
|
readonly onPause: Subject<void>;
|
|
16
18
|
readonly onStop: Subject<void>;
|
|
@@ -20,13 +22,25 @@ export declare class PlayerController {
|
|
|
20
22
|
private trackId;
|
|
21
23
|
readonly status: BehaviorSubject<PlayerStatus | null>;
|
|
22
24
|
readonly playing: import("rxjs").Observable<boolean>;
|
|
25
|
+
private playerElement;
|
|
23
26
|
private localStorage;
|
|
24
|
-
|
|
27
|
+
private options;
|
|
28
|
+
private defaultOptions;
|
|
29
|
+
private destroyEvent;
|
|
30
|
+
private fadeIntervalSubscription?;
|
|
31
|
+
private fadePromiseResolve?;
|
|
32
|
+
constructor(trackId: string, trackUrl: string, options?: PlayerControllerOptions);
|
|
25
33
|
open(id: string, file: string): Promise<void>;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
destroy(): Promise<void>;
|
|
35
|
+
play(options?: {
|
|
36
|
+
fadeIn?: boolean;
|
|
37
|
+
}): Promise<void>;
|
|
38
|
+
fadeIn(): Promise<void>;
|
|
39
|
+
fadeOut(): Promise<void>;
|
|
40
|
+
private clearFade;
|
|
41
|
+
pause(options?: {
|
|
42
|
+
fadeIn?: boolean;
|
|
43
|
+
}): Promise<void>;
|
|
30
44
|
seekTo(seconds: number): void;
|
|
31
45
|
back(seconds?: number): void;
|
|
32
46
|
forward(seconds?: number): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"player-controller.d.ts","sourceRoot":"","sources":["../../src/player/player-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAsB,OAAO,
|
|
1
|
+
{"version":3,"file":"player-controller.d.ts","sourceRoot":"","sources":["../../src/player/player-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAsB,OAAO,EAA8B,MAAM,MAAM,CAAC;AAGhG,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,oBAAY,YAAY;IACtB,SAAS,YAAY;IACrB,QAAQ,WAAW;IACnB,OAAO,UAAU;CAClB;AAED,qBAAa,gBAAgB;IAC3B,SAAgB,MAAM,gBAAuB;IAC7C,SAAgB,OAAO,gBAAuB;IAC9C,SAAgB,MAAM,gBAAuB;IAE7C,SAAgB,WAAW,0BAAkC;IAC7D,SAAgB,SAAS,0BAAkC;IAC3D,SAAgB,QAAQ,oCAEtB;IAEF,OAAO,CAAC,OAAO,CAAuB;IAEtC,SAAgB,MAAM,uCAAkD;IACxE,SAAgB,OAAO,qCAA2D;IAElF,OAAO,CAAC,aAAa,CAAmB;IAExC,OAAO,CAAC,YAAY,CAA0C;IAE9D,OAAO,CAAC,OAAO,CAAoF;IACnG,OAAO,CAAC,cAAc,CAEpB;IAEF,OAAO,CAAC,YAAY,CAAuB;IAE3C,OAAO,CAAC,wBAAwB,CAAC,CAAS;IAC1C,OAAO,CAAC,kBAAkB,CAAC,CAAa;gBAE5B,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B;IA+D9E,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAQ7B,OAAO;IAQP,IAAI,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAO;IASvC,MAAM;IAiBN,OAAO;IAgBb,OAAO,CAAC,SAAS;IAKX,KAAK,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAO;IAQ9C,MAAM,CAAC,OAAO,EAAE,MAAM;IAOtB,IAAI,CAAC,OAAO,GAAE,MAAW;IAOzB,OAAO,CAAC,OAAO,GAAE,MAAW;YAQd,YAAY;IAK1B,OAAO,CAAC,GAAG;CAOZ"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BehaviorSubject, combineLatest, map, Subject } from "rxjs";
|
|
1
|
+
import { BehaviorSubject, combineLatest, map, Subject, take, takeUntil, takeWhile } from "rxjs";
|
|
2
2
|
import { LocalStorage } from "../storage/local-storage";
|
|
3
3
|
export var PlayerStatus;
|
|
4
4
|
(function (PlayerStatus) {
|
|
@@ -7,8 +7,6 @@ export var PlayerStatus;
|
|
|
7
7
|
PlayerStatus["ended"] = "ended";
|
|
8
8
|
})(PlayerStatus || (PlayerStatus = {}));
|
|
9
9
|
export class PlayerController {
|
|
10
|
-
playerElement;
|
|
11
|
-
options;
|
|
12
10
|
onPlay = new Subject();
|
|
13
11
|
onPause = new Subject();
|
|
14
12
|
onStop = new Subject();
|
|
@@ -18,36 +16,18 @@ export class PlayerController {
|
|
|
18
16
|
trackId = null;
|
|
19
17
|
status = new BehaviorSubject(null);
|
|
20
18
|
playing = this.status.pipe(map((status) => status === "playing"));
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// multiple times as part of a sequence and this is not the last call in that sequence.
|
|
34
|
-
if (details.fastSeek !== true && details.seekTime !== undefined)
|
|
35
|
-
this.seekTo(details.seekTime);
|
|
36
|
-
});
|
|
37
|
-
this.status.subscribe((status) => {
|
|
38
|
-
switch (status) {
|
|
39
|
-
case "playing":
|
|
40
|
-
navigator.mediaSession.playbackState = "playing";
|
|
41
|
-
break;
|
|
42
|
-
case "paused":
|
|
43
|
-
navigator.mediaSession.playbackState = "paused";
|
|
44
|
-
break;
|
|
45
|
-
default:
|
|
46
|
-
case "ended":
|
|
47
|
-
navigator.mediaSession.playbackState = "none";
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
});
|
|
19
|
+
playerElement;
|
|
20
|
+
localStorage = new LocalStorage({ prefix: "player" });
|
|
21
|
+
options;
|
|
22
|
+
defaultOptions = {
|
|
23
|
+
fadeInterval: 2000,
|
|
24
|
+
};
|
|
25
|
+
destroyEvent = new Subject();
|
|
26
|
+
fadeIntervalSubscription;
|
|
27
|
+
fadePromiseResolve;
|
|
28
|
+
constructor(trackId, trackUrl, options = {}) {
|
|
29
|
+
this.options = { ...this.defaultOptions, ...options };
|
|
30
|
+
this.playerElement = this.options.audioElement ?? new Audio();
|
|
51
31
|
this.playerElement.addEventListener("play", () => {
|
|
52
32
|
this.onPlay.next();
|
|
53
33
|
this.status.next(PlayerStatus.playing);
|
|
@@ -66,19 +46,31 @@ export class PlayerController {
|
|
|
66
46
|
}
|
|
67
47
|
});
|
|
68
48
|
this.playerElement.addEventListener("timeupdate", () => {
|
|
69
|
-
navigator.mediaSession.setPositionState({
|
|
70
|
-
duration: Number.isNaN(this.playerElement.duration) ? 0 : this.playerElement.duration,
|
|
71
|
-
playbackRate: this.playerElement.playbackRate,
|
|
72
|
-
position: this.playerElement.currentTime,
|
|
73
|
-
});
|
|
74
49
|
this.currentTime.next(this.playerElement.currentTime);
|
|
75
50
|
if (this.playerElement.duration) {
|
|
76
51
|
this.totalTime.next(this.playerElement.duration);
|
|
77
52
|
}
|
|
78
|
-
if (this.options.autoSave) {
|
|
79
|
-
this.savePosition(this.playerElement.currentTime);
|
|
80
|
-
}
|
|
81
53
|
});
|
|
54
|
+
if (this.options.autoSave) {
|
|
55
|
+
this.currentTime.pipe(takeUntil(this.destroyEvent)).subscribe((currentTime) => this.savePosition(currentTime));
|
|
56
|
+
}
|
|
57
|
+
if (this.options.fadeOut && !this.options.loop) {
|
|
58
|
+
combineLatest([this.currentTime, this.totalTime])
|
|
59
|
+
.pipe(takeUntil(this.destroyEvent))
|
|
60
|
+
.pipe(takeWhile(([currentTime, totalTime]) => totalTime - currentTime < this.options.fadeInterval), take(1))
|
|
61
|
+
.subscribe(async (currentTime) => {
|
|
62
|
+
this.onStop.next();
|
|
63
|
+
this.fadeOut();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (this.options.loop) {
|
|
67
|
+
this.onStop.pipe(takeUntil(this.destroyEvent)).subscribe(() => {
|
|
68
|
+
this.playerElement.currentTime = 0;
|
|
69
|
+
this.playerElement.play();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
this.open(trackId, trackUrl);
|
|
73
|
+
this.log("Initialized player", this.playerElement);
|
|
82
74
|
}
|
|
83
75
|
async open(id, file) {
|
|
84
76
|
this.trackId = id;
|
|
@@ -86,33 +78,59 @@ export class PlayerController {
|
|
|
86
78
|
const position = await this.localStorage.get(`progress-${this.trackId}`, (value) => typeof value === "number");
|
|
87
79
|
if (position && this.options.autoSave)
|
|
88
80
|
this.playerElement.currentTime = position;
|
|
89
|
-
if (this.options.playOnInit)
|
|
90
|
-
await this.playerElement.play();
|
|
91
81
|
}
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
async destroy() {
|
|
83
|
+
this.destroyEvent.next();
|
|
84
|
+
await this.pause();
|
|
85
|
+
this.playerElement.remove();
|
|
94
86
|
}
|
|
95
|
-
|
|
96
|
-
this.playerElement.pause();
|
|
97
|
-
// this.playerElement.src = "";
|
|
98
|
-
navigator.mediaSession.setActionHandler("play", null);
|
|
99
|
-
navigator.mediaSession.setActionHandler("pause", null);
|
|
100
|
-
navigator.mediaSession.setActionHandler("previoustrack", null);
|
|
101
|
-
navigator.mediaSession.setActionHandler("nexttrack", null);
|
|
102
|
-
navigator.mediaSession.playbackState = "none";
|
|
103
|
-
navigator.mediaSession.metadata = null;
|
|
104
|
-
}
|
|
105
|
-
play() {
|
|
87
|
+
async play(options = {}) {
|
|
106
88
|
if (!this.playerElement.src)
|
|
107
89
|
throw new Error("No file opened");
|
|
108
90
|
this.log("Called play");
|
|
109
|
-
this.playerElement?.play();
|
|
91
|
+
await this.playerElement?.play();
|
|
92
|
+
if (options.fadeIn !== undefined ? options.fadeIn : this.options.fadeIn)
|
|
93
|
+
await this.fadeIn();
|
|
94
|
+
}
|
|
95
|
+
async fadeIn() {
|
|
96
|
+
this.clearFade();
|
|
97
|
+
return new Promise((resolve) => {
|
|
98
|
+
this.playerElement.volume = 0;
|
|
99
|
+
this.fadePromiseResolve = resolve;
|
|
100
|
+
this.fadeIntervalSubscription = setInterval(() => {
|
|
101
|
+
if (this.playerElement.volume >= 1) {
|
|
102
|
+
clearInterval(this.fadeIntervalSubscription);
|
|
103
|
+
return resolve();
|
|
104
|
+
}
|
|
105
|
+
this.playerElement.volume = Math.min(this.playerElement.volume + (1 / this.options.fadeInterval) * 100, 1);
|
|
106
|
+
}, 100);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async fadeOut() {
|
|
110
|
+
this.clearFade();
|
|
111
|
+
return new Promise((resolve) => {
|
|
112
|
+
this.fadePromiseResolve = resolve;
|
|
113
|
+
this.fadeIntervalSubscription = setInterval(() => {
|
|
114
|
+
if (this.playerElement.volume <= 0) {
|
|
115
|
+
clearInterval(this.fadeIntervalSubscription);
|
|
116
|
+
this.playerElement.pause();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.playerElement.volume = Math.max(this.playerElement.volume - (1 / this.options.fadeInterval) * 100, 0);
|
|
120
|
+
}, 100);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
clearFade() {
|
|
124
|
+
clearInterval(this.fadeIntervalSubscription);
|
|
125
|
+
this.fadePromiseResolve?.();
|
|
110
126
|
}
|
|
111
|
-
pause() {
|
|
127
|
+
async pause(options = {}) {
|
|
112
128
|
if (!this.playerElement.src)
|
|
113
129
|
throw new Error("No file opened");
|
|
114
130
|
this.log("Called pause");
|
|
115
131
|
this.playerElement?.pause();
|
|
132
|
+
if (options.fadeIn !== undefined ? options.fadeIn : this.options.fadeIn)
|
|
133
|
+
await this.fadeOut();
|
|
116
134
|
}
|
|
117
135
|
seekTo(seconds) {
|
|
118
136
|
if (!this.playerElement.src)
|
|
@@ -138,10 +156,10 @@ export class PlayerController {
|
|
|
138
156
|
return;
|
|
139
157
|
await this.localStorage.set(`progress-${this.trackId}`, currentTime);
|
|
140
158
|
}
|
|
141
|
-
log(message) {
|
|
159
|
+
log(message, ...args) {
|
|
142
160
|
const time = this.playerElement?.currentTime ? Math.round(this.playerElement?.currentTime) : null;
|
|
143
161
|
if (time)
|
|
144
162
|
message += ` @${time}s`;
|
|
145
|
-
console.log(`[PlayerController] ${message}
|
|
163
|
+
console.log(`[PlayerController] ${message}`, ...args);
|
|
146
164
|
}
|
|
147
165
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"story-controller.d.ts","sourceRoot":"","sources":["../../src/story/story-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"story-controller.d.ts","sourceRoot":"","sources":["../../src/story/story-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA6B,OAAO,EAAE,MAAM,MAAM,CAAC;AAG3E,MAAM,WAAW,sBAAsB,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,EAAE,UAAU,SAAS,EAAE,GAAG,EAAE;IACnG,EAAE,EAAE,SAAS,CAAC;IACd,WAAW,EAAE,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC;CAClH;AAED,MAAM,WAAW,eAAe,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM;IAChE,cAAc,EAAE,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB,CAAC,UAAU;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,KAAK,IAAI,UAAU,CAAC;CACrD;AAED,MAAM,WAAW,eAAe,CAC9B,SAAS,SAAS,MAAM,GAAG,MAAM,EACjC,UAAU,SAAS;IAAE,cAAc,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,eAAe,CAAC,SAAS,CAAC,EAC9E,iBAAiB,SAAS,sBAAsB,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,sBAAsB,CAC9F,SAAS,EACT,UAAU,CACX;IAED,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAC/C,YAAY,EAAE,UAAU,CAAC;CAC1B;AAED,qBAAa,eAAe,CAC1B,SAAS,SAAS,MAAM,GAAG,MAAM,EACjC,UAAU,SAAS;IAAE,cAAc,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,eAAe,CAAC,SAAS,CAAC,EAC9E,iBAAiB,SAAS,sBAAsB,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,sBAAsB,CAC9F,SAAS,EACT,UAAU,CACX;aAWiB,KAAK,EAAE,eAAe,CAAC,SAAS,EAAE,UAAU,EAAE,iBAAiB,CAAC;IAChF,OAAO,CAAC,OAAO;IAVjB,SAAgB,UAAU,8BAA8C;IACxE,SAAgB,cAAc,4CAAuD;IACrF,SAAgB,GAAG,gBAAuB;IAE1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAE5C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAW;gBAGzB,KAAK,EAAE,eAAe,CAAC,SAAS,EAAE,UAAU,EAAE,iBAAiB,CAAC,EACxE,OAAO,GAAE,sBAAsB,CAAC,UAAU,CAAM;IAgBpD,QAAQ,CAAC,KAAK,EAAE,UAAU;IAK1B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,UAAU,CAAC;IAa7E,UAAU,CAAC,MAAM,EAAE,SAAS;IAI5B,WAAW;IAuBX,UAAU;IAKhB,QAAQ;YAIM,SAAS;YAaT,SAAS;CAGxB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BehaviorSubject, map, Subject } from "rxjs";
|
|
1
|
+
import { BehaviorSubject, distinctUntilChanged, map, Subject } from "rxjs";
|
|
2
2
|
import { LocalStorage } from "../storage/local-storage";
|
|
3
3
|
export class StoryController {
|
|
4
4
|
story;
|
|
@@ -13,7 +13,9 @@ export class StoryController {
|
|
|
13
13
|
this.options = options;
|
|
14
14
|
this.localStorage = new LocalStorage({ prefix: options.stateStorageKey ?? "story-state" });
|
|
15
15
|
this.storyState
|
|
16
|
-
.pipe(map((state) =>
|
|
16
|
+
.pipe(map((state) => state.currentChapter))
|
|
17
|
+
.pipe(distinctUntilChanged())
|
|
18
|
+
.pipe(map((currentChapter) => (currentChapter ? story.chapters[currentChapter] : null)))
|
|
17
19
|
.subscribe(this.currentChapter);
|
|
18
20
|
this.loadState().then((state) => {
|
|
19
21
|
if (state)
|
|
@@ -53,13 +55,13 @@ export class StoryController {
|
|
|
53
55
|
if (typeof chapter.nextChapter === "function") {
|
|
54
56
|
const storyState = this.storyState.value;
|
|
55
57
|
const string = await chapter.nextChapter(storyState);
|
|
56
|
-
this.setChapter(string);
|
|
58
|
+
return this.setChapter(string);
|
|
57
59
|
}
|
|
58
60
|
throw new Error(`Invalid nextChapter type in chapter ${chapter.id}`);
|
|
59
61
|
}
|
|
60
62
|
async resetStory() {
|
|
61
|
-
await this.setState(this.story.initialState);
|
|
62
63
|
await LocalStorage.clearAll();
|
|
64
|
+
await this.setState(this.story.initialState);
|
|
63
65
|
}
|
|
64
66
|
endStory() {
|
|
65
67
|
this.end.next();
|