add pulse manipulate function in Pattern.
This commit is contained in:
parent
b3ddf3710e
commit
cbaf999692
|
@ -1,8 +1,9 @@
|
||||||
import { invoke } from '@tauri-apps/api/core';
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { atom, useSetAtom } from 'jotai';
|
import { atom, useAtomValue, useSetAtom } from 'jotai';
|
||||||
import { atomWithRefresh } from 'jotai/utils';
|
import { atomWithRefresh } from 'jotai/utils';
|
||||||
import { get, reduce } from 'lodash-es';
|
import { get, reduce } from 'lodash-es';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
import { NotificationType, ToastDuration, useNotification } from '../components/Notifications';
|
import { NotificationType, ToastDuration, useNotification } from '../components/Notifications';
|
||||||
|
|
||||||
|
@ -94,22 +95,76 @@ export class Pattern {
|
||||||
this.smoothRepeat = true;
|
this.smoothRepeat = true;
|
||||||
this.pulses = [];
|
this.pulses = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
movePulseUp(pulseId: string, step: number) {
|
||||||
|
const index = this.pulses.findIndex((pulse) => pulse.id === pulseId);
|
||||||
|
if (index === -1 || index - step < 0) return;
|
||||||
|
|
||||||
|
const targetIndex = index - step;
|
||||||
|
const targetPulse = this.pulses[targetIndex];
|
||||||
|
const currentPulse = this.pulses[index];
|
||||||
|
|
||||||
|
// Swap the pulses
|
||||||
|
this.pulses[targetIndex] = currentPulse;
|
||||||
|
this.pulses[index] = targetPulse;
|
||||||
|
|
||||||
|
// Swap their order
|
||||||
|
const tempOrder = currentPulse.order;
|
||||||
|
currentPulse.order = targetPulse.order;
|
||||||
|
targetPulse.order = tempOrder;
|
||||||
|
|
||||||
|
// Sort pulses by order
|
||||||
|
this.pulses.sort((a, b) => a.order - b.order);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createNewPulse(pattern: Pattern): Pulse {
|
movePulseDown(pulseId: string, step: number) {
|
||||||
const maxOrder = reduce(pattern.pulses, (former, pulse) => Math.max(former, pulse.order), 0);
|
const index = this.pulses.findIndex((pulse) => pulse.id === pulseId);
|
||||||
if (pattern.smoothRepeat) {
|
if (index === -1 || index + step >= this.pulses.length) return;
|
||||||
return new Pulse(
|
|
||||||
|
const targetIndex = index + step;
|
||||||
|
const targetPulse = this.pulses[targetIndex];
|
||||||
|
const currentPulse = this.pulses[index];
|
||||||
|
|
||||||
|
// Swap the pulses
|
||||||
|
this.pulses[targetIndex] = currentPulse;
|
||||||
|
this.pulses[index] = targetPulse;
|
||||||
|
|
||||||
|
// Swap their order
|
||||||
|
const tempOrder = currentPulse.order;
|
||||||
|
currentPulse.order = targetPulse.order;
|
||||||
|
targetPulse.order = tempOrder;
|
||||||
|
|
||||||
|
// Sort pulses by order
|
||||||
|
this.pulses.sort((a, b) => a.order - b.order);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPulse(): Pulse {
|
||||||
|
const maxOrder = reduce(this.pulses, (former, pulse) => Math.max(former, pulse.order), 0);
|
||||||
|
const newPulse = new Pulse(
|
||||||
maxOrder + 1,
|
maxOrder + 1,
|
||||||
get(pattern.pulses, '[0].width', 0),
|
this.smoothRepeat ? get(this.pulses, '[0].width', 0) : get(this.pulses, '[-1].width', 0),
|
||||||
get(pattern.pulses, '[0].frequency', 1),
|
this.smoothRepeat
|
||||||
);
|
? get(this.pulses, '[0].frequency', 1)
|
||||||
} else {
|
: get(this.pulses, '[-1].frequency', 1),
|
||||||
return new Pulse(
|
|
||||||
maxOrder + 1,
|
|
||||||
get(pattern.pulses, '[-1].width', 0),
|
|
||||||
get(pattern.pulses, '[-1].frequency', 1),
|
|
||||||
);
|
);
|
||||||
|
this.pulses.push(newPulse);
|
||||||
|
return newPulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePulse(pulseId: string, pulse: Pulse) {
|
||||||
|
const index = this.pulses.findIndex((p) => p.id === pulseId);
|
||||||
|
if (index !== -1) {
|
||||||
|
const { id, order, ...rest } = pulse;
|
||||||
|
this.pulses[index] = { ...this.pulses[index], ...rest };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deletePulse(pulseId: string) {
|
||||||
|
this.pulses = this.pulses.filter((pulse) => pulse.id !== pulseId);
|
||||||
|
this.pulses.sort((a, b) => a.order - b.order);
|
||||||
|
this.pulses.forEach((pulse, index) => {
|
||||||
|
pulse.order = index + 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +188,7 @@ export const PatternsAtom = atomWithRefresh(async (get) => {
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
export const SelectedPatternIdAtom = atom<string | null>(null);
|
export const SelectedPatternIdAtom = atom<string | null>(null);
|
||||||
export const CurrentPatternAtom = atom<Pattern | null>(async (get) => {
|
export const CurrentPatternAtom = atomWithRefresh<Pattern | null>(async (get) => {
|
||||||
try {
|
try {
|
||||||
const patternId = get(SelectedPatternIdAtom);
|
const patternId = get(SelectedPatternIdAtom);
|
||||||
if (patternId === null) {
|
if (patternId === null) {
|
||||||
|
@ -146,38 +201,35 @@ export const CurrentPatternAtom = atom<Pattern | null>(async (get) => {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
export const PulsesInCurrentPatternAtom = atom(
|
export const PulsesInCurrentPatternAtom = atomWithRefresh(
|
||||||
(get) => get(CurrentPatternAtom)?.pulses ?? [],
|
(get) => get(CurrentPatternAtom)?.pulses ?? [],
|
||||||
(get, set, pulse: Pulse) => {
|
|
||||||
const currentPulses = get(CurrentPatternAtom)?.pulses ?? [];
|
|
||||||
const newPulses = currentPulses.map((p) => (p.id === pulse.id ? pulse : p));
|
|
||||||
if (!newPulses.some((p) => p.id === pulse.id)) {
|
|
||||||
newPulses.push(pulse);
|
|
||||||
}
|
|
||||||
newPulses.sort((a, b) => a.order - b.order);
|
|
||||||
const currentPattern = get(CurrentPatternAtom);
|
|
||||||
if (currentPattern) {
|
|
||||||
set(CurrentPatternAtom, {
|
|
||||||
...currentPattern,
|
|
||||||
pulses: newPulses,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
export const CurrentPatternDuration = atom((get) => {
|
export const CurrentPatternDuration = atom((get) => {
|
||||||
const currentPattern = get(CurrentPatternAtom);
|
const currentPattern = get(CurrentPatternAtom);
|
||||||
if (!currentPattern) return 0;
|
if (!currentPattern) return 0;
|
||||||
return totalDuration(currentPattern);
|
return totalDuration(currentPattern);
|
||||||
});
|
});
|
||||||
|
export const SelectedPulseIdAtom = atom<string | null>(null);
|
||||||
|
export const SelectedPulseAtom = atom<Pulse | null>((get) => {
|
||||||
|
const pulses = get(PulsesInCurrentPatternAtom);
|
||||||
|
const selectedPulseId = get(SelectedPulseIdAtom);
|
||||||
|
return pulses.find((pulse) => pulse.id === selectedPulseId) ?? null;
|
||||||
|
});
|
||||||
|
|
||||||
export function useSavePattern() {
|
export function useSavePattern() {
|
||||||
const refreshPatterns = useSetAtom(PatternsAtom);
|
const refreshPatterns = useSetAtom(PatternsAtom);
|
||||||
|
const selectedPatternId = useAtomValue(SelectedPatternIdAtom);
|
||||||
|
const refreshSelectedPattern = useSetAtom(CurrentPatternAtom);
|
||||||
const { showToast } = useNotification();
|
const { showToast } = useNotification();
|
||||||
|
|
||||||
const savePattern = async (pattern: Pattern) => {
|
const savePattern = useCallback(
|
||||||
|
async (pattern: Pattern) => {
|
||||||
try {
|
try {
|
||||||
await invoke('save_pattern', { pattern });
|
await invoke('save_pattern', { pattern });
|
||||||
refreshPatterns();
|
refreshPatterns();
|
||||||
|
if (pattern.id === selectedPatternId) {
|
||||||
|
refreshSelectedPattern();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[save pattern]', error);
|
console.error('[save pattern]', error);
|
||||||
|
@ -189,7 +241,9 @@ export function useSavePattern() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
},
|
||||||
|
[selectedPatternId],
|
||||||
|
);
|
||||||
|
|
||||||
return savePattern;
|
return savePattern;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user