···11# Changelog
2233+## Next
44+- Make macOS media key permission request non-intrusive
55+36## 0.19.9 - 2025 Jul 4
47- Fix column size not updating when resizing window
58- Fix column sorting not working
+67-2
src/App.svelte
···11<script lang="ts">
22 import { onDestroy, onMount } from 'svelte'
33- import { fade } from 'svelte/transition'
33+ import { fade, fly } from 'svelte/transition'
44 import TrackList from './components/TrackList.svelte'
55 import Player from './components/Player.svelte'
66 import Sidebar from './components/Sidebar.svelte'
···2323 import './lib/router'
2424 import CheckForUpdates from './components/CheckForUpdates.svelte'
2525 import Settings from './components/Settings.svelte'
2626+ import Button from './components/Button.svelte'
26272728 ipc_renderer.invoke('app_loaded').catch(() => {
2829 ipc_renderer.invoke('showMessageBox', false, {
···3132 detail: 'Graceful shutdown will not be possible.',
3233 })
3334 })
3535+3636+ let media_keys_result: Awaited<ReturnType<typeof init_media_keys>> | null = null
3737+ async function init_media_keys(prompt: boolean) {
3838+ return await ipc_renderer.invoke('init_media_keys', prompt)
3939+ }
4040+ init_media_keys(false).then((result) => (media_keys_result = result))
34413542 async function open_import_dialog() {
3643 if ($modal_count !== 0) {
···179186 })
180187</script>
181188182182-<svelte:window on:keydown={keydown} />
189189+<svelte:window
190190+ on:keydown={keydown}
191191+ on:focus={async () => {
192192+ if (media_keys_result?.needs_accessibility_permission) {
193193+ media_keys_result = null
194194+ media_keys_result = await ipc_renderer.invoke('init_media_keys', false)
195195+ }
196196+ }}
197197+/>
183198<svelte:head>
184199 <title>Ferrum</title>
185200</svelte:head>
···204219 <div class="flex size-full min-w-0 flex-col">
205220 <Route route="/playlist/:playlist_id" component={TrackList} />
206221 <Route route="/artists" component={ArtistList} />
222222+ {#if media_keys_result}
223223+ <div class="shrink-0 overflow-hidden">
224224+ <div
225225+ class="flex items-center border-t border-r border-l border-red-500/15 bg-red-500/10 px-2 py-1 text-[15px] text-red-500 select-text"
226226+ in:fly|global={{ y: '100%', duration: 200 }}
227227+ >
228228+ {#if media_keys_result.error}
229229+ {media_keys_result.error}
230230+ <Button
231231+ type="button"
232232+ secondary
233233+ thin
234234+ on:click={async () => {
235235+ media_keys_result = null
236236+ media_keys_result = await ipc_renderer.invoke('init_media_keys', false)
237237+ }}>Retry</Button
238238+ >
239239+ <Button
240240+ type="button"
241241+ secondary
242242+ thin
243243+ on:click={() => {
244244+ media_keys_result = null
245245+ }}>Ignore</Button
246246+ >
247247+ {:else if media_keys_result.needs_accessibility_permission}
248248+ Do you want to Ferrum to control the media keys? You may need to delete and re-add the
249249+ app from the accessibility list
250250+ <Button
251251+ class="text-nowrap"
252252+ type="button"
253253+ secondary
254254+ thin
255255+ on:click={async () => {
256256+ media_keys_result = null
257257+ media_keys_result = await ipc_renderer.invoke('init_media_keys', true)
258258+ }}>Give permission</Button
259259+ >
260260+ <Button
261261+ type="button"
262262+ secondary
263263+ thin
264264+ on:click={() => {
265265+ media_keys_result = null
266266+ }}>Ignore</Button
267267+ >
268268+ {/if}
269269+ </div>
270270+ </div>
271271+ {/if}
207272 </div>
208273 {#if $queue_visible}
209274 <Queue />