mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-26 12:08:27 +00:00
fix(app): decouple completion chime
Play the completion sound through the app with Web Audio so it is not tied to whether desktop notifications are enabled or whether a platform-specific notification sound name is supported. Keep the notification body focused on completion status and leave the settings toggle available even when notifications are disabled.
This commit is contained in:
+34
-15
@@ -42,9 +42,34 @@ const getScheduledQueueIds = () => {
|
||||
return selectedQueueIds;
|
||||
};
|
||||
|
||||
type AudioContextConstructor = typeof AudioContext;
|
||||
|
||||
const playCompletionChime = () => {
|
||||
const AudioCtor =
|
||||
window.AudioContext ||
|
||||
(window as Window & { webkitAudioContext?: AudioContextConstructor }).webkitAudioContext;
|
||||
if (!AudioCtor) return;
|
||||
|
||||
const context = new AudioCtor();
|
||||
const oscillator = context.createOscillator();
|
||||
const gain = context.createGain();
|
||||
oscillator.type = 'sine';
|
||||
oscillator.frequency.setValueAtTime(880, context.currentTime);
|
||||
oscillator.frequency.exponentialRampToValueAtTime(1320, context.currentTime + 0.12);
|
||||
gain.gain.setValueAtTime(0.0001, context.currentTime);
|
||||
gain.gain.exponentialRampToValueAtTime(0.18, context.currentTime + 0.02);
|
||||
gain.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 0.24);
|
||||
oscillator.connect(gain);
|
||||
gain.connect(context.destination);
|
||||
oscillator.start();
|
||||
oscillator.stop(context.currentTime + 0.24);
|
||||
oscillator.onended = () => {
|
||||
void context.close();
|
||||
};
|
||||
};
|
||||
|
||||
function App() {
|
||||
const platform = usePlatformInfo();
|
||||
const platformOsRef = useRef(platform.os);
|
||||
const [filter, setFilter] = useState<SidebarFilter>('all');
|
||||
const [coreReady, setCoreReady] = useState(false);
|
||||
|
||||
@@ -115,10 +140,6 @@ function App() {
|
||||
|
||||
const { addToast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
platformOsRef.current = platform.os;
|
||||
}, [platform.os]);
|
||||
|
||||
useEffect(() => {
|
||||
let active = true;
|
||||
const initialize = async () => {
|
||||
@@ -520,24 +541,22 @@ function App() {
|
||||
const unlistenTerminalState = listen('download-state', (event) => {
|
||||
if (event.payload.status !== 'completed' && event.payload.status !== 'failed') return;
|
||||
const settings = useSettingsStore.getState();
|
||||
if (event.payload.status === 'completed' && settings.playCompletionSound) {
|
||||
try {
|
||||
playCompletionChime();
|
||||
} catch (error) {
|
||||
console.error('Completion sound failed:', error);
|
||||
}
|
||||
}
|
||||
if (!settings.showNotifications) return;
|
||||
|
||||
const item = useDownloadStore.getState().downloads.find(d => d.id === event.payload.id);
|
||||
const fileName = item?.fileName || 'A file';
|
||||
const platformOs = platformOsRef.current;
|
||||
const sound = settings.playCompletionSound
|
||||
? platformOs === 'macos'
|
||||
? 'Ping'
|
||||
: platformOs === 'linux'
|
||||
? 'message-new-instant'
|
||||
: undefined
|
||||
: undefined;
|
||||
if (event.payload.status === 'completed') {
|
||||
try {
|
||||
sendNotification({
|
||||
title: 'Download Complete',
|
||||
body: `${fileName} has finished downloading.`,
|
||||
sound
|
||||
body: `${fileName} has finished downloading.`
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Completion notification failed:', error);
|
||||
|
||||
@@ -526,19 +526,6 @@ runEngineChecks(false);
|
||||
className="app-control w-24 text-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="mac-settings-row">
|
||||
<div className="settings-row-label">
|
||||
<span>Global speed limit:</span>
|
||||
<small>{settings.globalSpeedLimit || 'Unlimited'}</small>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => settings.setActiveView('speedLimiter')}
|
||||
className="app-button px-3 text-xs"
|
||||
>
|
||||
Configure…
|
||||
</button>
|
||||
</div>
|
||||
<div className="mac-settings-row">
|
||||
<div className="settings-row-label">
|
||||
<span>Automatic retries:</span>
|
||||
@@ -571,12 +558,11 @@ runEngineChecks(false);
|
||||
className="mac-switch"
|
||||
/>
|
||||
</label>
|
||||
<label className="mac-settings-row cursor-default" style={{ opacity: settings.showNotifications ? 1 : 0.5 }}>
|
||||
<label className="mac-settings-row cursor-default">
|
||||
<span className="text-[13px] text-text-primary">Play sound when download completes</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={settings.playCompletionSound}
|
||||
disabled={!settings.showNotifications}
|
||||
onChange={(e) => settings.setPlayCompletionSound(e.target.checked)}
|
||||
className="mac-switch"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user