Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src-tauri/gen/schemas/acl-manifests.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src-tauri/permissions/dmnote-allow-all.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@
"sound_list",
"sound_load",
"sound_load_original",
"sound_rename",
"sound_save_processed_wav",
"sound_set_enabled",
"sound_update_processed_wav",
"stat_positions_get",
"stat_positions_update",
Expand Down
49 changes: 33 additions & 16 deletions src-tauri/src/commands/keys/sound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ pub struct SoundListItem {
pub size_bytes: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub modified_at_ms: Option<u64>,
pub enabled: bool,
pub source: SoundSource,
#[serde(skip_serializing_if = "Option::is_none")]
pub original_path: Option<String>,
Expand Down Expand Up @@ -70,16 +69,15 @@ pub struct SoundSaveProcessedWavResponse {

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SoundSetEnabledResponse {
pub struct SoundDeleteResponse {
pub success: bool,
pub sound_path: String,
pub enabled: bool,
}

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SoundDeleteResponse {
pub struct SoundRenameResponse {
pub success: bool,
pub display_name: String,
}

/// 로컬 사운드 파일을 선택하고 appData/sounds 디렉토리로 복사한 뒤 경로 반환
Expand Down Expand Up @@ -116,7 +114,6 @@ pub fn sound_load(
s.sound_library.insert(
dest_path_str.clone(),
SoundLibraryEntry {
enabled: true,
source: SoundSource::Local,
..Default::default()
},
Expand Down Expand Up @@ -190,7 +187,6 @@ pub fn sound_list(
file_name,
size_bytes: metadata.len(),
modified_at_ms,
enabled: entry_meta.enabled,
source: entry_meta.source,
original_path: entry_meta.original_path,
trim_start_ratio: entry_meta.trim_start_ratio,
Expand Down Expand Up @@ -235,27 +231,49 @@ pub fn sound_list(
}

#[tauri::command]
pub fn sound_set_enabled(
pub fn sound_rename(
app: tauri::AppHandle,
state: State<'_, AppState>,
sound_path: String,
enabled: bool,
) -> CmdResult<SoundSetEnabledResponse> {
display_name: String,
) -> CmdResult<SoundRenameResponse> {
let sounds_dir = ensure_sounds_dir(&app)?;
let validated_path = validate_sound_path(&sounds_dir, &sound_path)?;
if !validated_path.exists() {
return Err(CommandError::msg("대상 사운드 파일이 존재하지 않습니다."));
}

let path_key = normalize_path_string(&validated_path);

let trimmed = display_name.trim();
if trimmed.is_empty() {
return Err(CommandError::msg("사운드 이름이 비어 있습니다."));
}

// 내장 사운드 이름 변경 차단 (재시딩 시 원복됨)
let is_builtin = state.store.with_state(|s| {
s.sound_library
.get(&path_key)
.map(|entry| entry.source == SoundSource::Builtin)
});
let Some(is_builtin) = is_builtin else {
return Err(CommandError::msg("대상 사운드가 존재하지 않습니다."));
};
if is_builtin {
return Err(CommandError::msg(
"내장 사운드는 이름을 변경할 수 없습니다.",
));
}

let next_name = trimmed.to_string();
state.store.update(|s| {
s.sound_library.entry(path_key.clone()).or_default().enabled = enabled;
if let Some(entry) = s.sound_library.get_mut(&path_key) {
entry.display_name = Some(next_name.clone());
}
})?;

Ok(SoundSetEnabledResponse {
Ok(SoundRenameResponse {
success: true,
sound_path: path_key,
enabled,
display_name: next_name,
})
}

Expand Down Expand Up @@ -441,7 +459,6 @@ pub fn sound_save_processed_wav(
s.sound_library.insert(
dest_path_str.clone(),
SoundLibraryEntry {
enabled: true,
source: SoundSource::Local,
original_path: original_rel_path.clone(),
trim_start_ratio: request.trim_start_ratio,
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ fn main() {
commands::keys::key_sound::key_sound_get_output_state,
commands::keys::sound::sound_load,
commands::keys::sound::sound_list,
commands::keys::sound::sound_set_enabled,
commands::keys::sound::sound_rename,
commands::keys::sound::sound_delete,
commands::keys::sound::sound_save_processed_wav,
commands::keys::sound::sound_load_original,
Expand Down
7 changes: 0 additions & 7 deletions src-tauri/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,9 @@ fn default_sound_source() -> SoundSource {
SoundSource::Local
}

fn default_sound_enabled() -> bool {
true
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SoundLibraryEntry {
#[serde(default = "default_sound_enabled")]
pub enabled: bool,
#[serde(default = "default_sound_source")]
pub source: SoundSource,
#[serde(default, skip_serializing_if = "Option::is_none")]
Expand All @@ -86,7 +80,6 @@ pub struct SoundLibraryEntry {
impl Default for SoundLibraryEntry {
fn default() -> Self {
Self {
enabled: true,
source: SoundSource::Local,
original_path: None,
trim_start_ratio: None,
Expand Down
10 changes: 1 addition & 9 deletions src-tauri/src/state/builtin_sounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub(crate) fn seed_builtin_sounds(app_data_dir: &Path, data: &mut AppStoreData)
let key = dest.to_string_lossy().to_string();
match data.sound_library.get_mut(&key) {
Some(entry) => {
// enabled(사용자 토글)는 보존, source/표시 이름만 갱신
// source/표시 이름만 갱신, 트림 메타데이터는 보존
if entry.source != SoundSource::Builtin
|| entry.display_name.as_deref() != Some(sound.display_name)
{
Expand Down Expand Up @@ -98,19 +98,11 @@ mod tests {
.expect("library entry missing");
assert_eq!(entry.source, SoundSource::Builtin);
assert_eq!(entry.display_name.as_deref(), Some(sound.display_name));
assert!(entry.enabled);
}

// 재실행: 변경 없음 (멱등)
assert!(!seed_builtin_sounds(&dir, &mut data));

// 사용자 토글(enabled=false)은 재시딩에도 보존
for entry in data.sound_library.values_mut() {
entry.enabled = false;
}
assert!(!seed_builtin_sounds(&dir, &mut data));
assert!(data.sound_library.values().all(|entry| !entry.enabled));

// Local로 오염된 source는 자가 치유
for entry in data.sound_library.values_mut() {
entry.source = SoundSource::Local;
Expand Down
10 changes: 5 additions & 5 deletions src/renderer/api/modules/resourceApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ export const soundApi = {
invoke<import('@src/types/plugin/api').SoundLoadResult>('sound_load'),
list: () =>
invoke<import('@src/types/plugin/api').SoundListItem[]>('sound_list'),
setEnabled: (soundPath: string, enabled: boolean) =>
invoke<import('@src/types/plugin/api').SoundSetEnabledResult>(
'sound_set_enabled',
{ soundPath, enabled },
),
rename: (soundPath: string, displayName: string) =>
invoke<import('@src/types/plugin/api').SoundRenameResult>('sound_rename', {
soundPath,
displayName,
}),
remove: (soundPath: string) =>
invoke<import('@src/types/plugin/api').SoundDeleteResult>('sound_delete', {
soundPath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
import Checkbox from '@components/main/common/Checkbox';
import Dropdown from '@components/main/common/Dropdown';
import FontPicker from '@components/main/Modal/content/pickers/FontPicker';
import FontManagerModal from '@components/main/Modal/content/managers/FontManagerModal';
import CounterAnimationPicker from '@components/main/Modal/content/pickers/CounterAnimationPicker';

interface BatchKeyVisual {
Expand Down Expand Up @@ -78,7 +77,6 @@ const BatchCounterTabContent: React.FC<BatchCounterTabContentProps> = ({
const fontButtonRef = useRef<HTMLButtonElement>(null);
const animationButtonRef = useRef<HTMLButtonElement>(null);
const [showFontPicker, setShowFontPicker] = useState(false);
const [showFontManager, setShowFontManager] = useState(false);
const [showAnimationPicker, setShowAnimationPicker] = useState(false);

const handleAnimationUpdate = (
Expand Down Expand Up @@ -335,22 +333,10 @@ const BatchCounterTabContent: React.FC<BatchCounterTabContentProps> = ({
handleBatchCounterUpdate({ fontFamily });
}}
onClose={() => setShowFontPicker(false)}
onOpenManager={() => {
setShowFontManager(true);
}}
interactiveRefs={[fontButtonRef]}
/>
)}

{/* FontManagerModal */}
{showFontManager && (
<FontManagerModal
isOpen={showFontManager}
onClose={() => setShowFontManager(false)}
t={t}
/>
)}

{showAnimationPicker && (
<CounterAnimationPicker
open={showAnimationPicker}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
} from '../index';
import Checkbox from '@components/main/common/Checkbox';
import FontPicker from '@components/main/Modal/content/pickers/FontPicker';
import FontManagerModal from '@components/main/Modal/content/managers/FontManagerModal';
import SoundPicker from '@components/main/Modal/content/pickers/SoundPicker';

const SPACING_COMMIT_DEBOUNCE_MS = 80;
Expand Down Expand Up @@ -177,7 +176,6 @@ const BatchStyleTabContent: React.FC<BatchStyleTabContentProps> = ({
}
};
}, []);
const [showFontManager, setShowFontManager] = useState(false);
const fontButtonRef = useRef<HTMLButtonElement>(null);
const soundButtonRef = useRef<HTMLButtonElement>(null);

Expand Down Expand Up @@ -945,9 +943,6 @@ const BatchStyleTabContent: React.FC<BatchStyleTabContentProps> = ({
handleBatchStyleChangeComplete('fontFamily', fontName);
}}
onClose={() => setShowFontPicker(false)}
onOpenManager={() => {
setShowFontManager(true);
}}
interactiveRefs={[fontButtonRef]}
/>
)}
Expand Down Expand Up @@ -977,15 +972,6 @@ const BatchStyleTabContent: React.FC<BatchStyleTabContentProps> = ({
}
/>
)}

{/* FontManagerModal */}
{!hideFontControls && showFontManager && (
<FontManagerModal
isOpen={showFontManager}
onClose={() => setShowFontManager(false)}
t={t}
/>
)}
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import Checkbox from '@components/main/common/Checkbox';
import Dropdown from '@components/main/common/Dropdown';
import ColorPicker from '@components/main/Modal/content/pickers/ColorPicker';
import FontPicker from '@components/main/Modal/content/pickers/FontPicker';
import FontManagerModal from '@components/main/Modal/content/managers/FontManagerModal';
import CounterAnimationPicker from '@components/main/Modal/content/pickers/CounterAnimationPicker';

type PickerTarget = 'fill' | 'stroke' | 'font' | null;
Expand All @@ -39,7 +38,6 @@ const CounterTabContent: React.FC<CounterTabContentProps> = ({
const [pickerFor, setPickerFor] = useState<PickerTarget>(null);
const pickerOpen = pickerFor !== null && pickerFor !== 'font';
const [colorState, setColorState] = useState<ColorState>('idle');
const [showFontManager, setShowFontManager] = useState(false);
const [showAnimationPicker, setShowAnimationPicker] = useState(false);

const counterSettings = normalizeCounterSettings(keyPosition.counter);
Expand Down Expand Up @@ -405,22 +403,10 @@ const CounterTabContent: React.FC<CounterTabContentProps> = ({
handleCounterUpdate({ fontFamily: fontName });
}}
onClose={() => setPickerFor(null)}
onOpenManager={() => {
setShowFontManager(true);
}}
interactiveRefs={[fontBtnRef]}
/>
)}

{/* FontManagerModal */}
{showFontManager && (
<FontManagerModal
isOpen={showFontManager}
onClose={() => setShowFontManager(false)}
t={t}
/>
)}

{showAnimationPicker && (
<CounterAnimationPicker
open={showAnimationPicker}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
import ImagePicker from '../../../Modal/content/pickers/ImagePicker';
import ColorPicker from '../../../Modal/content/pickers/ColorPicker';
import FontPicker from '../../../Modal/content/pickers/FontPicker';
import FontManagerModal from '../../../Modal/content/managers/FontManagerModal';
import SoundPicker from '../../../Modal/content/pickers/SoundPicker';
import Checkbox from '../../../common/Checkbox';

Expand Down Expand Up @@ -102,8 +101,6 @@ const StyleTabContent: React.FC<StyleTabContentInternalProps> = ({
// 폰트 버튼 ref
const fontButtonRef = useRef<HTMLButtonElement>(null);
const soundButtonRef = useRef<HTMLButtonElement>(null);
// 폰트 관리 모달 상태
const [showFontManager, setShowFontManager] = useState(false);
const [showSoundPicker, setShowSoundPicker] = useState(false);
const borderColorBtnRef = useRef<HTMLButtonElement>(null);
const fontColorBtnRef = useRef<HTMLButtonElement>(null);
Expand Down Expand Up @@ -795,9 +792,6 @@ const StyleTabContent: React.FC<StyleTabContentInternalProps> = ({
handleStyleChangeComplete('fontFamily', fontName);
}}
onClose={() => setPickerFor(null)}
onOpenManager={() => {
setShowFontManager(true);
}}
interactiveRefs={[fontButtonRef]}
/>
)}
Expand All @@ -819,15 +813,6 @@ const StyleTabContent: React.FC<StyleTabContentInternalProps> = ({
previewVolume={keyPosition.soundVolume ?? 100}
/>
)}

{/* FontManagerModal */}
{showFontManager && (
<FontManagerModal
isOpen={showFontManager}
onClose={() => setShowFontManager(false)}
t={t}
/>
)}
</>
);
};
Expand Down
Loading
Loading