mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
feat: Replay Gain, Crossfade, Download Folder Modal, Changelog in Settings (v1.6.0)
### Audio - Replay Gain support (track + album mode, configurable pre-gain, hard limiter) - Crossfade between tracks (configurable duration 1–10 s) - Gapless preloading ⚠️ experimental/alpha — enable in Settings → Playback - Atomic sink swap: old track plays until new one is decoded, then stops cleanly ### UI / UX - Settings redesigned with tab navigation (General, Playback, About) - Changelog viewer in Settings → About with collapsible version entries - Download Folder Modal: choose folder + "remember" checkbox per-download - EQ popup now accessible directly from the Player Bar - "Also Featured On" section on Artist pages for non-album appearances ### Fixes - Bundle identifier changed from dev.psysonic.app → dev.psysonic.player (fixes macOS warning) - Version sync: all four version files (package.json, Cargo.toml, tauri.conf.json, PKGBUILD) now at 1.6.0 ### Known Issues - FLAC seeking via waveform seekbar does not work (MP3/OGG unaffected) — under investigation Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { FolderOpen } from 'lucide-react';
|
||||
import { open as openDialog } from '@tauri-apps/plugin-dialog';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDownloadModalStore } from '../store/downloadModalStore';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
|
||||
export default function DownloadFolderModal() {
|
||||
const { isOpen, folder, remember, setFolder, setRemember, confirm, cancel } = useDownloadModalStore();
|
||||
const setDownloadFolder = useAuthStore(s => s.setDownloadFolder);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleBrowse = async () => {
|
||||
const selected = await openDialog({ directory: true, multiple: false, title: t('common.chooseDownloadFolder') });
|
||||
if (selected && typeof selected === 'string') setFolder(selected);
|
||||
};
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="eq-popup-backdrop" onClick={cancel} style={{ zIndex: 210 }} />
|
||||
<div className="eq-popup" style={{ zIndex: 211, width: 'min(480px, 92vw)', gap: 0 }}>
|
||||
<div className="eq-popup-header">
|
||||
<span className="eq-popup-title">{t('common.chooseDownloadFolder')}</span>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: '16px 0 12px' }}>
|
||||
<div className="download-folder-pick-row">
|
||||
<span className="download-folder-path">
|
||||
{folder || t('common.noFolderSelected')}
|
||||
</span>
|
||||
<button className="btn btn-ghost" onClick={handleBrowse} style={{ flexShrink: 0 }}>
|
||||
<FolderOpen size={15} /> {t('settings.pickFolder')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<label className="download-remember-row">
|
||||
<input type="checkbox" checked={remember} onChange={e => setRemember(e.target.checked)} />
|
||||
<span>{t('common.rememberDownloadFolder')}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="download-modal-actions">
|
||||
<button className="btn btn-ghost" onClick={cancel}>{t('common.cancel')}</button>
|
||||
<button
|
||||
className="btn btn-primary"
|
||||
onClick={() => confirm(setDownloadFolder)}
|
||||
disabled={!folder}
|
||||
>
|
||||
{t('common.download')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user