initial scaffold

This commit is contained in:
Boof2015
2026-05-25 21:54:43 -04:00
parent 40c2302d97
commit 9761975af7
40 changed files with 10797 additions and 1 deletions
+44
View File
@@ -0,0 +1,44 @@
import { create } from 'zustand';
import type { EQBand } from '@/types/audio';
/**
* EQ state — M0 stub. The biquad chain is implemented as a Media3 AudioProcessor
* at M4; for now this just holds the band model (ported `EQBand`) so the EQ
* screen and later DSP wiring share one shape.
*/
const DEFAULT_FREQUENCIES = [32, 64, 125, 250, 500, 1000, 2000, 4000, 8000, 16000];
function makeDefaultBands(): EQBand[] {
return DEFAULT_FREQUENCIES.map((frequency) => ({
id: `band-${frequency}`,
type: 'peaking',
frequency,
gain: 0,
Q: 1.0,
}));
}
interface EQStore {
enabled: boolean;
preamp: number; // dB
bands: EQBand[];
setEnabled: (enabled: boolean) => void;
setPreamp: (preamp: number) => void;
setBandGain: (id: string, gain: number) => void;
reset: () => void;
}
export const useEQStore = create<EQStore>((set) => ({
enabled: false,
preamp: 0,
bands: makeDefaultBands(),
setEnabled: (enabled) => set({ enabled }),
setPreamp: (preamp) => set({ preamp }),
setBandGain: (id, gain) =>
set((state) => ({
bands: state.bands.map((b) => (b.id === id ? { ...b, gain } : b)),
})),
reset: () => set({ enabled: false, preamp: 0, bands: makeDefaultBands() }),
}));
+30
View File
@@ -0,0 +1,30 @@
import { create } from 'zustand';
import type { Album, Artist, DbTrack } from '@/types/library';
/**
* Library state — minimal M0 stub. Real on-device scanning + SQLite (op-sqlite)
* land at M1; the shapes here mirror desktop `libraryStore` so that work slots in.
*/
type ViewMode = 'tracks' | 'albums' | 'artists' | 'folders';
interface LibraryStore {
tracks: DbTrack[];
albums: Album[];
artists: Artist[];
totalTrackCount: number;
viewMode: ViewMode;
isScanning: boolean;
setViewMode: (mode: ViewMode) => void;
}
export const useLibraryStore = create<LibraryStore>((set) => ({
tracks: [],
albums: [],
artists: [],
totalTrackCount: 0,
viewMode: 'albums',
isScanning: false,
setViewMode: (viewMode) => set({ viewMode }),
}));
+41
View File
@@ -0,0 +1,41 @@
import { create } from 'zustand';
import type { PlaybackState, Track } from '@/types/audio';
/**
* Player state — the UI's single source of truth, mirrored from the playback
* engine (RNTP at M0) by `usePlaybackSync`. Field names match desktop
* `playerStore` so queue/transport logic ports cleanly. Setters are called by
* the sync layer and the playback controller, not directly by screens.
*/
interface PlayerStore {
currentTrack: Track | null;
playbackState: PlaybackState;
currentTime: number;
duration: number;
volume: number; // 01
isMuted: boolean;
setCurrentTrack: (track: Track | null) => void;
setPlaybackState: (state: PlaybackState) => void;
setProgress: (currentTime: number, duration: number) => void;
setVolume: (volume: number) => void;
setMuted: (isMuted: boolean) => void;
reset: () => void;
}
export const usePlayerStore = create<PlayerStore>((set) => ({
currentTrack: null,
playbackState: 'stopped',
currentTime: 0,
duration: 0,
volume: 1,
isMuted: false,
setCurrentTrack: (currentTrack) => set({ currentTrack }),
setPlaybackState: (playbackState) => set({ playbackState }),
setProgress: (currentTime, duration) => set({ currentTime, duration }),
setVolume: (volume) => set({ volume }),
setMuted: (isMuted) => set({ isMuted }),
reset: () =>
set({ currentTrack: null, playbackState: 'stopped', currentTime: 0, duration: 0 }),
}));