migrated to vue wtf
This commit is contained in:
196
src/BeatStore.ts
196
src/BeatStore.ts
@@ -1,136 +1,114 @@
|
||||
import Beat, { BeatEvents } from "@/Beat";
|
||||
import { Capsule, ICapsule, ISubscriber } from "@djledda/ladder";
|
||||
import { type Beat, createBeat, deserialise as deserialiseBeat } from "@/Beat";
|
||||
import { inject, computed, type InjectionKey, ref, shallowRef, triggerRef, watch } from "vue";
|
||||
|
||||
const EventTypeSubscriptions = [
|
||||
BeatEvents.TimeSigUpChanged,
|
||||
BeatEvents.BarCountChanged,
|
||||
BeatEvents.GlobalDisplayTypeChanged,
|
||||
BeatEvents.TrackListChanged,
|
||||
BeatEvents.LockingChanged,
|
||||
BeatEvents.AutoBeatSettingsChanged,
|
||||
BeatEvents.DeepChange,
|
||||
] as const;
|
||||
type EventTypeSubscriptions = typeof EventTypeSubscriptions[number];
|
||||
function defaultMainBeatGroup(): Beat {
|
||||
const defaultSettings = {
|
||||
barCount: 2,
|
||||
isLooping: false,
|
||||
timeSigUp: 8,
|
||||
};
|
||||
const mainBeatGroup = createBeat(defaultSettings);
|
||||
mainBeatGroup.addTrack({ name: "LF" });
|
||||
mainBeatGroup.addTrack({ name: "LH" });
|
||||
mainBeatGroup.addTrack({ name: "RH" });
|
||||
mainBeatGroup.addTrack({ name: "RF" });
|
||||
return mainBeatGroup;
|
||||
}
|
||||
|
||||
export default class BeatStore implements ISubscriber<EventTypeSubscriptions> {
|
||||
private readonly beats: Beat[];
|
||||
private activeBeat: ICapsule<Beat>;
|
||||
private onBeatChangeCbs: (() => void)[] = [];
|
||||
private autoSave: boolean;
|
||||
private orientation: "horizontal" | "vertical" | null = null;
|
||||
export function createBeatStore() {
|
||||
const beats = shallowRef<Beat[]>([ defaultMainBeatGroup() ]);
|
||||
const activeBeatIndex = ref(0);
|
||||
const activeBeat = computed<Beat | null>(() => beats.value[activeBeatIndex.value] ?? null);
|
||||
const autoSave = ref(true);
|
||||
const orientation = ref<'horizontal' | 'vertical' | null>(null);
|
||||
|
||||
constructor(options: { loadFromLocalStorage: boolean, autoSave: boolean }) {
|
||||
this.autoSave = options.autoSave;
|
||||
if (options.loadFromLocalStorage) {
|
||||
const save = localStorage.getItem("drum-slayer-save");
|
||||
if (save) {
|
||||
const serial = JSON.parse(save);
|
||||
this.beats = [BeatStore.defaultMainBeatGroup()];
|
||||
this.activeBeat = Capsule.new(this.beats[0]);
|
||||
this.loadFromSave(serial);
|
||||
if (this.autoSave) {
|
||||
this.activeBeat.watch(() => this.save("localStorage"), true);
|
||||
this.beats.forEach(beat => beat.addSubscriber(this, EventTypeSubscriptions));
|
||||
}
|
||||
return;
|
||||
}
|
||||
function resetActiveBeat(): void {
|
||||
const current = activeBeat.value;
|
||||
beats.value[activeBeatIndex.value] = defaultMainBeatGroup();
|
||||
current?.destroy();
|
||||
triggerRef(beats);
|
||||
}
|
||||
|
||||
function removeBeat(index: number): void {
|
||||
const beat = beats.value[index];
|
||||
beats.value.splice(index, 1);
|
||||
beat?.destroy();
|
||||
triggerRef(beats);
|
||||
}
|
||||
|
||||
function addNewBeat(): void {
|
||||
const newBeat = defaultMainBeatGroup();
|
||||
beats.value.push(newBeat);
|
||||
if (autoSave.value) {
|
||||
save("localStorage");
|
||||
}
|
||||
this.beats = [
|
||||
BeatStore.defaultMainBeatGroup(),
|
||||
];
|
||||
this.activeBeat = Capsule.new(this.beats[0]);
|
||||
triggerRef(beats);
|
||||
}
|
||||
|
||||
notify(publisher: unknown, event: EventTypeSubscriptions): void {
|
||||
this.save("localStorage");
|
||||
}
|
||||
|
||||
static defaultMainBeatGroup(): Beat {
|
||||
const defaultSettings = {
|
||||
barCount: 2,
|
||||
isLooping: false,
|
||||
timeSigUp: 8,
|
||||
};
|
||||
const mainBeatGroup = new Beat(defaultSettings);
|
||||
mainBeatGroup.addTrack({ name: "LF" });
|
||||
mainBeatGroup.addTrack({ name: "LH" });
|
||||
mainBeatGroup.addTrack({ name: "RH" });
|
||||
mainBeatGroup.addTrack({ name: "RF" });
|
||||
return mainBeatGroup;
|
||||
}
|
||||
|
||||
getActiveBeat(): ICapsule<Beat> {
|
||||
return this.activeBeat;
|
||||
}
|
||||
|
||||
resetActiveBeat(): void {
|
||||
const index = this.beats.indexOf(this.activeBeat.val);
|
||||
const reset = BeatStore.defaultMainBeatGroup();
|
||||
this.beats[index] = reset;
|
||||
this.activeBeat.val = reset;
|
||||
}
|
||||
|
||||
getBeats(): Beat[] {
|
||||
return this.beats.slice();
|
||||
}
|
||||
|
||||
setActiveBeat(beat: Beat): void {
|
||||
const index = this.beats.indexOf(beat);
|
||||
if (index !== -1) {
|
||||
this.activeBeat.val = this.beats[index];
|
||||
}
|
||||
}
|
||||
|
||||
addNewBeat(): void {
|
||||
const newBeat = BeatStore.defaultMainBeatGroup();
|
||||
this.beats.push(newBeat);
|
||||
if (this.autoSave) {
|
||||
newBeat.addSubscriber(this, EventTypeSubscriptions);
|
||||
}
|
||||
this.onBeatChangeCbs.forEach(cb => cb());
|
||||
if (this.autoSave) {
|
||||
this.save("localStorage");
|
||||
}
|
||||
}
|
||||
|
||||
onBeatChanges(callback: () => void) {
|
||||
this.onBeatChangeCbs.push(callback);
|
||||
}
|
||||
|
||||
save(destination: "localStorage"): void {
|
||||
function save(destination: "localStorage"): void {
|
||||
if (destination === "localStorage") {
|
||||
const serials = this.beats.map(beat => beat.serialise());
|
||||
const serials = beats.value.map(beat => beat.serialise());
|
||||
localStorage.setItem("drum-slayer-save", JSON.stringify({
|
||||
beats: serials,
|
||||
activeBeatIndex: this.beats.indexOf(this.activeBeat.val),
|
||||
orientation: this.orientation,
|
||||
activeBeatIndex: activeBeatIndex.value,
|
||||
orientation: orientation.value,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
loadFromSave(source: any): void {
|
||||
this.beats.length = 0;
|
||||
function loadFromSave(source: any): void {
|
||||
beats.value.length = 0;
|
||||
if (Array.isArray(source.beats)
|
||||
&& (typeof source.activeBeatIndex === "number" || typeof source.activeBeatIndex === "undefined")
|
||||
&& typeof source.orientation === "string") {
|
||||
try {
|
||||
source.beats.forEach((beat: any) => this.beats.push(Beat.deserialise(beat)));
|
||||
source.beats.forEach((beat: any) => beats.value.push(deserialiseBeat(beat)));
|
||||
if (typeof source.activeBeatIndex === "number") {
|
||||
this.activeBeat.val = this.beats[source.activeBeatIndex];
|
||||
activeBeatIndex.value = source.activeBeatIndex;
|
||||
}
|
||||
this.orientation = source.orientation;
|
||||
orientation.value = source.orientation;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
} else {
|
||||
resetActiveBeat();
|
||||
}
|
||||
}
|
||||
|
||||
setOrientation(orientation: "horizontal" | "vertical"): void {
|
||||
this.orientation = orientation;
|
||||
this.save("localStorage");
|
||||
|
||||
function bakeAll(): void {
|
||||
activeBeat.value?.bakeLoops();
|
||||
}
|
||||
|
||||
getSavedOrientation(): "horizontal" | "vertical" | null {
|
||||
return this.orientation;
|
||||
watch([activeBeatIndex, orientation, beats], () => {
|
||||
save('localStorage');
|
||||
});
|
||||
|
||||
const savedItem = localStorage.getItem('drum-slayer-save');
|
||||
if (savedItem) {
|
||||
const serial = JSON.parse(savedItem);
|
||||
beats.value = [defaultMainBeatGroup()];
|
||||
loadFromSave(serial);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
beats,
|
||||
activeBeatIndex,
|
||||
activeBeat,
|
||||
autoSave,
|
||||
orientation,
|
||||
|
||||
save,
|
||||
addNewBeat,
|
||||
removeBeat,
|
||||
resetActiveBeat,
|
||||
bakeAll,
|
||||
};
|
||||
}
|
||||
|
||||
export type BeatStore = ReturnType<typeof createBeatStore>;
|
||||
|
||||
export const BeatStoreKey = Symbol('BeatStore') as InjectionKey<BeatStore>;
|
||||
|
||||
export function useBeatStore(): BeatStore {
|
||||
return inject(BeatStoreKey, createBeatStore, true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user