refactor progress
This commit is contained in:
@@ -17,17 +17,23 @@
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Logger} from '@app/lib/Logger';
|
||||
import {makePersistent} from '@app/lib/MobXPersistence';
|
||||
import * as SoundUtils from '@app/utils/SoundUtils';
|
||||
import {SoundType} from '@app/utils/SoundUtils';
|
||||
import {makeAutoObservable, runInAction} from 'mobx';
|
||||
import {makePersistent} from '~/lib/MobXPersistence';
|
||||
import * as SoundUtils from '~/utils/SoundUtils';
|
||||
import {SoundType} from '~/utils/SoundUtils';
|
||||
|
||||
interface SoundSettings {
|
||||
export interface SoundSettings {
|
||||
allSoundsDisabled: boolean;
|
||||
disabledSounds: Partial<Record<SoundType, boolean>>;
|
||||
}
|
||||
|
||||
class SoundStore {
|
||||
private logger = new Logger('SoundStore');
|
||||
private inFlightLoopSounds = new Set<SoundType>();
|
||||
private pendingLoopSounds = new Set<SoundType>();
|
||||
private loopPlayTokens = new Map<SoundType, number>();
|
||||
private unlockListenersAttached = false;
|
||||
currentlyPlaying = new Set<SoundType>();
|
||||
volume = 0.7;
|
||||
incomingCallActive = false;
|
||||
@@ -37,10 +43,17 @@ class SoundStore {
|
||||
};
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(
|
||||
makeAutoObservable<
|
||||
SoundStore,
|
||||
'inFlightLoopSounds' | 'pendingLoopSounds' | 'loopPlayTokens' | 'unlockListenersAttached'
|
||||
>(
|
||||
this,
|
||||
{
|
||||
currentlyPlaying: false,
|
||||
inFlightLoopSounds: false,
|
||||
pendingLoopSounds: false,
|
||||
loopPlayTokens: false,
|
||||
unlockListenersAttached: false,
|
||||
},
|
||||
{autoBind: true},
|
||||
);
|
||||
@@ -56,9 +69,30 @@ class SoundStore {
|
||||
return;
|
||||
}
|
||||
|
||||
SoundUtils.playSound(sound, loop, this.volume)
|
||||
if (loop) {
|
||||
if (this.isPlayingSound(sound) || this.inFlightLoopSounds.has(sound) || this.pendingLoopSounds.has(sound)) {
|
||||
return;
|
||||
}
|
||||
this.inFlightLoopSounds.add(sound);
|
||||
}
|
||||
|
||||
const token = loop ? this.bumpLoopToken(sound) : 0;
|
||||
|
||||
SoundUtils.playSound(sound, loop, this.volume, () => {
|
||||
if (loop) {
|
||||
this.queuePendingLoopSound(sound);
|
||||
}
|
||||
})
|
||||
.then((result) => {
|
||||
if (loop) {
|
||||
this.inFlightLoopSounds.delete(sound);
|
||||
}
|
||||
if (result) {
|
||||
if (loop && this.getLoopToken(sound) !== token) {
|
||||
void SoundUtils.stopSound(sound);
|
||||
return;
|
||||
}
|
||||
this.clearPendingLoopSound(sound);
|
||||
runInAction(() => {
|
||||
const newPlaying = new Set(this.currentlyPlaying);
|
||||
newPlaying.add(sound);
|
||||
@@ -66,10 +100,18 @@ class SoundStore {
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error) => console.warn('Failed to play sound:', error));
|
||||
.catch((error) => {
|
||||
if (loop) {
|
||||
this.inFlightLoopSounds.delete(sound);
|
||||
}
|
||||
this.logger.warn('Failed to play sound:', error);
|
||||
});
|
||||
}
|
||||
|
||||
stopSound(sound: SoundType): void {
|
||||
this.bumpLoopToken(sound);
|
||||
this.inFlightLoopSounds.delete(sound);
|
||||
this.clearPendingLoopSound(sound);
|
||||
SoundUtils.stopSound(sound);
|
||||
const newPlaying = new Set(this.currentlyPlaying);
|
||||
newPlaying.delete(sound);
|
||||
@@ -77,14 +119,23 @@ class SoundStore {
|
||||
}
|
||||
|
||||
stopAllSounds(): void {
|
||||
this.clearPendingLoopSounds();
|
||||
this.inFlightLoopSounds.clear();
|
||||
this.loopPlayTokens.clear();
|
||||
SoundUtils.stopAllSounds();
|
||||
this.currentlyPlaying = new Set();
|
||||
this.incomingCallActive = false;
|
||||
}
|
||||
|
||||
startIncomingRing(): void {
|
||||
this.playSound(SoundType.IncomingRing, true);
|
||||
this.incomingCallActive = true;
|
||||
if (this.isPlayingSound(SoundType.IncomingRing) || this.inFlightLoopSounds.has(SoundType.IncomingRing)) {
|
||||
return;
|
||||
}
|
||||
if (this.pendingLoopSounds.has(SoundType.IncomingRing)) {
|
||||
return;
|
||||
}
|
||||
this.playSound(SoundType.IncomingRing, true);
|
||||
}
|
||||
|
||||
stopIncomingRing(): void {
|
||||
@@ -102,7 +153,7 @@ class SoundStore {
|
||||
allSoundsDisabled: !this.settings.allSoundsDisabled,
|
||||
};
|
||||
if (this.settings.allSoundsDisabled) {
|
||||
SoundUtils.stopAllSounds();
|
||||
this.stopAllSounds();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +180,9 @@ class SoundStore {
|
||||
...this.settings,
|
||||
disabledSounds: newDisabledSounds,
|
||||
};
|
||||
if (!enabled) {
|
||||
this.clearPendingLoopSound(soundType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +213,90 @@ class SoundStore {
|
||||
isPlayingSound(sound: SoundType): boolean {
|
||||
return this.currentlyPlaying.has(sound);
|
||||
}
|
||||
|
||||
private bumpLoopToken(sound: SoundType): number {
|
||||
const nextToken = (this.loopPlayTokens.get(sound) ?? 0) + 1;
|
||||
this.loopPlayTokens.set(sound, nextToken);
|
||||
return nextToken;
|
||||
}
|
||||
|
||||
private getLoopToken(sound: SoundType): number {
|
||||
return this.loopPlayTokens.get(sound) ?? 0;
|
||||
}
|
||||
|
||||
private queuePendingLoopSound(sound: SoundType): void {
|
||||
if (this.pendingLoopSounds.has(sound)) {
|
||||
return;
|
||||
}
|
||||
this.pendingLoopSounds.add(sound);
|
||||
this.attachUnlockListeners();
|
||||
}
|
||||
|
||||
private clearPendingLoopSound(sound: SoundType): void {
|
||||
if (this.pendingLoopSounds.delete(sound)) {
|
||||
this.detachUnlockListenersIfIdle();
|
||||
}
|
||||
}
|
||||
|
||||
private clearPendingLoopSounds(): void {
|
||||
this.pendingLoopSounds.clear();
|
||||
this.detachUnlockListeners();
|
||||
}
|
||||
|
||||
private attachUnlockListeners(): void {
|
||||
if (this.unlockListenersAttached) {
|
||||
return;
|
||||
}
|
||||
this.unlockListenersAttached = true;
|
||||
window.addEventListener('pointerdown', this.handleAutoplayUnlock, {passive: true});
|
||||
window.addEventListener('keydown', this.handleAutoplayUnlock);
|
||||
}
|
||||
|
||||
private detachUnlockListenersIfIdle(): void {
|
||||
if (this.pendingLoopSounds.size > 0) {
|
||||
return;
|
||||
}
|
||||
this.detachUnlockListeners();
|
||||
}
|
||||
|
||||
private detachUnlockListeners(): void {
|
||||
if (!this.unlockListenersAttached) {
|
||||
return;
|
||||
}
|
||||
window.removeEventListener('pointerdown', this.handleAutoplayUnlock);
|
||||
window.removeEventListener('keydown', this.handleAutoplayUnlock);
|
||||
this.unlockListenersAttached = false;
|
||||
}
|
||||
|
||||
private handleAutoplayUnlock(): void {
|
||||
this.retryPendingLoopSounds();
|
||||
}
|
||||
|
||||
private retryPendingLoopSounds(): void {
|
||||
if (this.pendingLoopSounds.size === 0) {
|
||||
this.detachUnlockListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const sound of Array.from(this.pendingLoopSounds)) {
|
||||
if (!this.isSoundEnabled(sound)) {
|
||||
this.pendingLoopSounds.delete(sound);
|
||||
continue;
|
||||
}
|
||||
if (sound === SoundType.IncomingRing && !this.incomingCallActive) {
|
||||
this.pendingLoopSounds.delete(sound);
|
||||
continue;
|
||||
}
|
||||
if (this.isPlayingSound(sound) || this.inFlightLoopSounds.has(sound)) {
|
||||
this.pendingLoopSounds.delete(sound);
|
||||
continue;
|
||||
}
|
||||
this.pendingLoopSounds.delete(sound);
|
||||
this.playSound(sound, true);
|
||||
}
|
||||
|
||||
this.detachUnlockListenersIfIdle();
|
||||
}
|
||||
}
|
||||
|
||||
export default new SoundStore();
|
||||
|
||||
Reference in New Issue
Block a user