feat: persist global track visibility status and metronome status
This commit is contained in:
+28
-2
@@ -54,11 +54,19 @@ export class KGProject {
|
||||
@WithDefault(1)
|
||||
private pianoRollZoom: number = 1;
|
||||
|
||||
@Expose()
|
||||
@WithDefault(false)
|
||||
private showGlobalTracks: boolean = false;
|
||||
|
||||
@Expose()
|
||||
@WithDefault(false)
|
||||
private isMetronomeEnabled: boolean = false;
|
||||
|
||||
@Expose()
|
||||
@WithDefault(0)
|
||||
private projectStructureVersion: number = 0;
|
||||
|
||||
public static readonly CURRENT_PROJECT_STRUCTURE_VERSION: number = 15;
|
||||
public static readonly CURRENT_PROJECT_STRUCTURE_VERSION: number = 16;
|
||||
|
||||
@Expose()
|
||||
@Type(() => KGTrack, {
|
||||
@@ -89,7 +97,7 @@ export class KGProject {
|
||||
private globalTracks: KGGlobalTrack[] = createDefaultGlobalTracks();
|
||||
|
||||
// Constructor
|
||||
constructor(name: string = RESERVED_PROJECT_NAME, maxBars: number = 32, currentBars: number = 0, bpm: number = TIME_CONSTANTS.DEFAULT_BPM, timeSignature: TimeSignature = { numerator: 4, denominator: 4 }, keySignature: KeySignature = "C major", selectedMode: string = "ionian", isLooping: boolean = false, loopingRange: [number, number] = [0, 0], barWidthMultiplier: number = 2, tracks: KGTrack[] = [], projectStructureVersion: number = KGProject.CURRENT_PROJECT_STRUCTURE_VERSION, pianoRollZoom: number = 1, globalTracks: KGGlobalTrack[] = createDefaultGlobalTracks()) {
|
||||
constructor(name: string = RESERVED_PROJECT_NAME, maxBars: number = 32, currentBars: number = 0, bpm: number = TIME_CONSTANTS.DEFAULT_BPM, timeSignature: TimeSignature = { numerator: 4, denominator: 4 }, keySignature: KeySignature = "C major", selectedMode: string = "ionian", isLooping: boolean = false, loopingRange: [number, number] = [0, 0], barWidthMultiplier: number = 2, tracks: KGTrack[] = [], projectStructureVersion: number = KGProject.CURRENT_PROJECT_STRUCTURE_VERSION, pianoRollZoom: number = 1, globalTracks: KGGlobalTrack[] = createDefaultGlobalTracks(), showGlobalTracks: boolean = false, isMetronomeEnabled: boolean = false) {
|
||||
this.name = name;
|
||||
this.maxBars = maxBars;
|
||||
this.currentBars = currentBars;
|
||||
@@ -104,6 +112,8 @@ export class KGProject {
|
||||
this.projectStructureVersion = projectStructureVersion;
|
||||
this.pianoRollZoom = pianoRollZoom;
|
||||
this.globalTracks = globalTracks;
|
||||
this.showGlobalTracks = showGlobalTracks;
|
||||
this.isMetronomeEnabled = isMetronomeEnabled;
|
||||
}
|
||||
|
||||
// Getters
|
||||
@@ -188,6 +198,22 @@ export class KGProject {
|
||||
return this.projectStructureVersion;
|
||||
}
|
||||
|
||||
public getShowGlobalTracks(): boolean {
|
||||
return this.showGlobalTracks;
|
||||
}
|
||||
|
||||
public setShowGlobalTracks(showGlobalTracks: boolean): void {
|
||||
this.showGlobalTracks = showGlobalTracks;
|
||||
}
|
||||
|
||||
public getIsMetronomeEnabled(): boolean {
|
||||
return this.isMetronomeEnabled;
|
||||
}
|
||||
|
||||
public setIsMetronomeEnabled(isMetronomeEnabled: boolean): void {
|
||||
this.isMetronomeEnabled = isMetronomeEnabled;
|
||||
}
|
||||
|
||||
public getIsLooping(): boolean {
|
||||
return this.isLooping;
|
||||
}
|
||||
|
||||
@@ -163,6 +163,20 @@ describe('KGProjectStorage', () => {
|
||||
expect(loaded!.getPianoRollZoom()).toBe(5);
|
||||
});
|
||||
|
||||
it('preserves persisted global-track visibility and metronome state when saving and loading', async () => {
|
||||
const project = createTestProject('Toggle Song');
|
||||
project.setShowGlobalTracks(true);
|
||||
project.setIsMetronomeEnabled(true);
|
||||
|
||||
await storage.save('Toggle Song', project);
|
||||
|
||||
const loaded = await storage.load('Toggle Song');
|
||||
|
||||
expect(loaded).not.toBeNull();
|
||||
expect(loaded!.getShowGlobalTracks()).toBe(true);
|
||||
expect(loaded!.getIsMetronomeEnabled()).toBe(true);
|
||||
});
|
||||
|
||||
it('preserves global tracks and marker regions when saving and loading', async () => {
|
||||
const project = createTestProject('Marker Song');
|
||||
const markerTrack = project.getGlobalTracks().find(track => track.getType() === GlobalTrackType.Marker);
|
||||
|
||||
@@ -14,6 +14,7 @@ import { upgradeToV12 } from './upgradeToV12';
|
||||
import { upgradeToV13 } from './upgradeToV13';
|
||||
import { upgradeToV14 } from './upgradeToV14';
|
||||
import { upgradeToV15 } from './upgradeToV15';
|
||||
import { upgradeToV16 } from './upgradeToV16';
|
||||
|
||||
/**
|
||||
* Upgrade the given project to the latest structure version, one version at a time.
|
||||
@@ -93,6 +94,10 @@ export function upgradeProjectToLatest(project: KGProject): KGProject {
|
||||
workingProject = upgradeToV15(workingProject);
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
workingProject = upgradeToV16(workingProject);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// If an upgrader is missing, throw to prevent loading incompatible structures
|
||||
throw new Error(`No upgrader found for project structure version ${nextVersion}`);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { KGProject } from '../KGProject';
|
||||
import { upgradeProjectToLatest } from './KGProjectUpgrader';
|
||||
import { upgradeToV16 } from './upgradeToV16';
|
||||
|
||||
describe('upgradeToV16', () => {
|
||||
it('defaults persisted UI/audio toggles to false for legacy projects', () => {
|
||||
const project = new KGProject('Legacy', 32, 0, 125, undefined, undefined, undefined, undefined, [0, 0], 1, [], 15, 1, []);
|
||||
|
||||
upgradeToV16(project);
|
||||
|
||||
expect(project.getProjectStructureVersion()).toBe(16);
|
||||
expect(project.getShowGlobalTracks()).toBe(false);
|
||||
expect(project.getIsMetronomeEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it('preserves existing persisted toggle values through the main upgrader path', () => {
|
||||
const project = new KGProject('Legacy', 32, 0, 125, undefined, undefined, undefined, undefined, [0, 0], 1, [], 15, 1, [], true, true);
|
||||
|
||||
const upgraded = upgradeProjectToLatest(project);
|
||||
|
||||
expect(upgraded.getProjectStructureVersion()).toBe(KGProject.CURRENT_PROJECT_STRUCTURE_VERSION);
|
||||
expect(upgraded.getShowGlobalTracks()).toBe(true);
|
||||
expect(upgraded.getIsMetronomeEnabled()).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { KGProject } from '../KGProject';
|
||||
|
||||
export function upgradeToV16(project: KGProject): KGProject {
|
||||
try {
|
||||
if (typeof project.getShowGlobalTracks() !== 'boolean') {
|
||||
project.setShowGlobalTracks(false);
|
||||
}
|
||||
|
||||
if (typeof project.getIsMetronomeEnabled() !== 'boolean') {
|
||||
project.setIsMetronomeEnabled(false);
|
||||
}
|
||||
} finally {
|
||||
project.setProjectStructureVersion(16);
|
||||
}
|
||||
|
||||
return project;
|
||||
}
|
||||
Reference in New Issue
Block a user