[READ-ONLY] Mirror of https://github.com/probablykasper/ferrum. Music library app for Mac, Linux and Windows ferrum.kasper.space
electron linux macos music music-library music-player napi windows
0

Configure Feed

Select the types of activity you want to include in your feed.

Remove `on_track_info` props

Kasper (Sep 15, 2024, 9:13 PM +0200) 6221f7df fc386b48

+193 -193
+4 -19
src/App.svelte
··· 5 5 import Player from './components/Player.svelte' 6 6 import Sidebar from './components/Sidebar.svelte' 7 7 import Queue from './components/Queue.svelte' 8 - import TrackInfo, { type TrackInfoList } from './components/TrackInfo.svelte' 8 + import TrackInfo from './components/TrackInfo.svelte' 9 9 import PlaylistInfoModal from './components/PlaylistInfo.svelte' 10 10 import { queue_visible } from './lib/queue' 11 11 import { ipc_listen, ipc_renderer } from '@/lib/window' ··· 21 21 import { play_pause } from './lib/player' 22 22 import DragGhost from './components/DragGhost.svelte' 23 23 import ItunesImport from './components/ItunesImport.svelte' 24 - import type { TrackID } from 'ferrum-addon/addon' 25 24 import { modal_count } from './components/Modal.svelte' 26 25 import QuickNav from './components/QuickNav.svelte' 27 26 import { check_shortcut } from './lib/helpers' ··· 117 116 }), 118 117 ) 119 118 120 - let track_info_list: TrackInfoList | null = null 121 - function on_track_info(ids: TrackID[], track_index: number) { 122 - if ($modal_count === 0) { 123 - track_info_list = { ids, index: track_index } 124 - } 125 - } 126 - onDestroy( 127 - ipc_listen('context.Get Info', (_, ids: TrackID[], track_index: number) => { 128 - on_track_info(ids, track_index) 129 - }), 130 - ) 131 - 132 119 let playlist_info: PlaylistInfo | null = null 133 120 onDestroy( 134 121 ipc_listen('context.playlist.edit', (_, id) => { ··· 226 213 {/if} 227 214 </div> 228 215 {#if $page.viewAs === 0} 229 - <TrackList {on_track_info} /> 216 + <TrackList /> 230 217 {:else} 231 218 <ArtistList /> 232 219 {/if} 233 220 </div> 234 221 {#if $queue_visible} 235 - <Queue {on_track_info} /> 222 + <Queue /> 236 223 {/if} 237 224 </div> 238 225 <Player /> ··· 253 240 {/if} 254 241 </main> 255 242 256 - {#if track_info_list} 257 - <TrackInfo current_list={track_info_list} cancel={() => (track_info_list = null)} /> 258 - {/if} 243 + <TrackInfo /> 259 244 {#if playlist_info} 260 245 <PlaylistInfoModal info={playlist_info} cancel={() => (playlist_info = null)} /> 261 246 {/if}
+2 -3
src/components/Queue.svelte
··· 19 19 import * as dragGhost from './DragGhost.svelte' 20 20 import { ipc_listen, ipc_renderer } from '@/lib/window' 21 21 import { assert_unreachable, check_shortcut } from '@/lib/helpers' 22 - import type { TrackID } from 'ferrum-addon/addon' 23 22 import { fly } from 'svelte/transition' 24 23 import VirtualListBlock, { scroll_container_keydown } from './VirtualListBlock.svelte' 24 + import { open_track_info } from './TrackInfo.svelte' 25 25 26 26 let object_urls: string[] = [] 27 27 ··· 82 82 onDestroy(ipc_listen('context.Remove from Queue', remove_from_queue)) 83 83 84 84 let queue_element: HTMLElement 85 - export let on_track_info: (allIds: TrackID[], index: number) => void 86 85 87 86 const track_action_unlisten = ipc_listen('selectedTracksAction', (_, action) => { 88 87 let first_index = selection.findFirst() ··· 101 100 } else if (action === 'Get Info') { 102 101 const all_items = [...$queue.user_queue, ...$queue.auto_queue] 103 102 const all_ids = all_items.map((item) => item.id) 104 - on_track_info(all_ids, first_index) 103 + open_track_info(all_ids, first_index) 105 104 } else if (action === 'revealTrackFile') { 106 105 const track = methods.getTrack(queue.getByQueueIndex(first_index).id) 107 106 ipc_renderer.invoke('revealTrackFile', paths.tracksDir, track.file)
+185 -167
src/components/TrackInfo.svelte
··· 3 3 ids: TrackID[] 4 4 index: number 5 5 } 6 + 7 + const current_list = writable<TrackInfoList | null>(null) 8 + 9 + export function open_track_info(ids: TrackID[], index: number) { 10 + if (get(modal_count) === 0) { 11 + current_list.set({ ids, index }) 12 + } 13 + } 6 14 </script> 7 15 8 16 <script lang="ts"> 9 - import Modal from './Modal.svelte' 10 17 import { check_shortcut } from '@/lib/helpers' 11 18 import Button from './Button.svelte' 12 19 import { methods } from '@/lib/data' 13 20 import type { Track, TrackID } from '../../ferrum-addon' 14 - import { ipc_renderer } from '@/lib/window' 21 + import { ipc_listen, ipc_renderer } from '@/lib/window' 15 22 import { playing_id, reload } from '@/lib/player' 16 23 import { onDestroy, tick } from 'svelte' 24 + import { get, writable } from 'svelte/store' 25 + import Modal, { modal_count } from './Modal.svelte' 17 26 18 - export let current_list: TrackInfoList 19 - export let cancel: () => void 27 + onDestroy( 28 + ipc_listen('context.Get Info', (_, ids: TrackID[], track_index: number) => { 29 + open_track_info(ids, track_index) 30 + }), 31 + ) 32 + 33 + function cancel() { 34 + current_list.set(null) 35 + } 20 36 let id: TrackID 21 37 let track: Track 22 38 type ImageStuff = { ··· 28 44 /** Undefined when loading, null when no image exists */ 29 45 let image: ImageStuff | null | undefined 30 46 31 - $: open_index(current_list) 47 + $: if ($current_list) open_index($current_list) 32 48 function open_index(list: TrackInfoList) { 33 49 id = list.ids[list.index] 34 50 track = methods.getTrack(list.ids[list.index]) ··· 61 77 }) 62 78 63 79 function open_prev() { 64 - if (current_list.index > 0) { 65 - current_list.index -= 1 80 + if ($current_list && $current_list.index > 0) { 81 + $current_list.index -= 1 66 82 } 67 83 } 68 84 function open_next() { 69 - if (current_list.index + 1 < current_list.ids.length) { 70 - current_list.index += 1 85 + if ($current_list && $current_list.index + 1 < $current_list.ids.length) { 86 + $current_list.index += 1 71 87 } 72 88 } 73 89 ··· 303 319 304 320 <svelte:window on:keydown={keydown} /> 305 321 <svelte:body on:keydown|self={keydown_none_selected} on:paste={cover_paste} /> 306 - <Modal on_cancel={cancel} cancel_on_escape form={save}> 307 - <main class="modal"> 308 - <div class="header" class:has-subtitle={image && image.totalImages >= 2}> 309 - <div 310 - class="cover-area" 311 - class:droppable 312 - tabindex="0" 313 - on:keydown={cover_keydown} 314 - role="button" 315 - aria-label="Cover artwork" 316 - > 317 - <!-- svelte-ignore a11y-no-static-element-interactions --> 322 + {#if $current_list} 323 + <Modal on_cancel={cancel} cancel_on_escape form={save}> 324 + <main class="modal"> 325 + <div class="header" class:has-subtitle={image && image.totalImages >= 2}> 318 326 <div 319 - class="cover" 320 - on:dragenter={drag_enter_or_over} 321 - on:dragover={drag_enter_or_over} 322 - on:dragleave={drag_leave} 323 - on:drop={drop} 324 - on:dblclick={pick_cover} 327 + class="cover-area" 328 + class:droppable 329 + tabindex="0" 330 + on:keydown={cover_keydown} 331 + role="button" 332 + aria-label="Cover artwork" 325 333 > 326 - {#if image} 327 - <img class="outline-element" alt="" src={image.objectUrl} /> 328 - {:else if image === null} 329 - <svg 330 - class="cover-svg outline-element" 331 - xmlns="http://www.w3.org/2000/svg" 332 - width="8" 333 - height="8" 334 - viewBox="0 0 24 24" 335 - > 336 - <path 337 - d="M23 0l-15.996 3.585v13.04c-2.979-.589-6.004 1.671-6.004 4.154 0 2.137 1.671 3.221 3.485 3.221 2.155 0 4.512-1.528 4.515-4.638v-10.9l12-2.459v8.624c-2.975-.587-6 1.664-6 4.141 0 2.143 1.715 3.232 3.521 3.232 2.14 0 4.476-1.526 4.479-4.636v-17.364z" 338 - /> 339 - </svg> 340 - {:else} 341 - <!-- empty when loading --> 342 - {/if} 343 - </div> 344 - {#if image && image.totalImages >= 2} 345 - {@const image_index = image.index} 346 - <div class="cover-subtitle"> 347 - <div class="arrow" class:unclickable={image_index <= 0}> 348 - <!-- svelte-ignore a11y-click-events-have-key-events --> 334 + <!-- svelte-ignore a11y-no-static-element-interactions --> 335 + <div 336 + class="cover" 337 + on:dragenter={drag_enter_or_over} 338 + on:dragover={drag_enter_or_over} 339 + on:dragleave={drag_leave} 340 + on:drop={drop} 341 + on:dblclick={pick_cover} 342 + > 343 + {#if image} 344 + <img class="outline-element" alt="" src={image.objectUrl} /> 345 + {:else if image === null} 349 346 <svg 350 - on:click={prev_image} 351 - tabindex="-1" 352 - role="button" 353 - aria-label="Previous image" 354 - clip-rule="evenodd" 355 - fill-rule="evenodd" 356 - stroke-linejoin="round" 357 - stroke-miterlimit="2" 358 - width="18" 359 - height="18" 360 - fill="currentColor" 361 - viewBox="0 0 24 24" 347 + class="cover-svg outline-element" 362 348 xmlns="http://www.w3.org/2000/svg" 363 - ><path 364 - d="m13.789 7.155c.141-.108.3-.157.456-.157.389 0 .755.306.755.749v8.501c0 .445-.367.75-.755.75-.157 0-.316-.05-.457-.159-1.554-1.203-4.199-3.252-5.498-4.258-.184-.142-.29-.36-.29-.592 0-.23.107-.449.291-.591 1.299-1.002 3.945-3.044 5.498-4.243z" 365 - /></svg 366 - > 367 - </div> 368 - <div class="subtitle-text"> 369 - {image.index + 1} / {image.totalImages} 370 - </div> 371 - <div class="arrow" class:unclickable={image_index >= image.totalImages - 1}> 372 - <!-- svelte-ignore a11y-click-events-have-key-events --> 373 - <svg 374 - on:click={next_image} 375 - tabindex="-1" 376 - role="button" 377 - aria-label="Next image" 378 - clip-rule="evenodd" 379 - fill-rule="evenodd" 380 - stroke-linejoin="round" 381 - stroke-miterlimit="2" 382 - width="18" 383 - height="18" 384 - fill="currentColor" 349 + width="8" 350 + height="8" 385 351 viewBox="0 0 24 24" 386 - xmlns="http://www.w3.org/2000/svg" 387 - ><path 388 - d="m10.211 7.155c-.141-.108-.3-.157-.456-.157-.389 0-.755.306-.755.749v8.501c0 .445.367.75.755.75.157 0 .316-.05.457-.159 1.554-1.203 4.199-3.252 5.498-4.258.184-.142.29-.36.29-.592 0-.23-.107-.449-.291-.591-1.299-1.002-3.945-3.044-5.498-4.243z" 389 - /></svg 390 352 > 391 - </div> 353 + <path 354 + d="M23 0l-15.996 3.585v13.04c-2.979-.589-6.004 1.671-6.004 4.154 0 2.137 1.671 3.221 3.485 3.221 2.155 0 4.512-1.528 4.515-4.638v-10.9l12-2.459v8.624c-2.975-.587-6 1.664-6 4.141 0 2.143 1.715 3.232 3.521 3.232 2.14 0 4.476-1.526 4.479-4.636v-17.364z" 355 + /> 356 + </svg> 357 + {:else} 358 + <!-- empty when loading --> 359 + {/if} 392 360 </div> 393 - {/if} 361 + {#if image && image.totalImages >= 2} 362 + {@const image_index = image.index} 363 + <div class="cover-subtitle"> 364 + <div class="arrow" class:unclickable={image_index <= 0}> 365 + <!-- svelte-ignore a11y-click-events-have-key-events --> 366 + <svg 367 + on:click={prev_image} 368 + tabindex="-1" 369 + role="button" 370 + aria-label="Previous image" 371 + clip-rule="evenodd" 372 + fill-rule="evenodd" 373 + stroke-linejoin="round" 374 + stroke-miterlimit="2" 375 + width="18" 376 + height="18" 377 + fill="currentColor" 378 + viewBox="0 0 24 24" 379 + xmlns="http://www.w3.org/2000/svg" 380 + ><path 381 + d="m13.789 7.155c.141-.108.3-.157.456-.157.389 0 .755.306.755.749v8.501c0 .445-.367.75-.755.75-.157 0-.316-.05-.457-.159-1.554-1.203-4.199-3.252-5.498-4.258-.184-.142-.29-.36-.29-.592 0-.23.107-.449.291-.591 1.299-1.002 3.945-3.044 5.498-4.243z" 382 + /></svg 383 + > 384 + </div> 385 + <div class="subtitle-text"> 386 + {image.index + 1} / {image.totalImages} 387 + </div> 388 + <div class="arrow" class:unclickable={image_index >= image.totalImages - 1}> 389 + <!-- svelte-ignore a11y-click-events-have-key-events --> 390 + <svg 391 + on:click={next_image} 392 + tabindex="-1" 393 + role="button" 394 + aria-label="Next image" 395 + clip-rule="evenodd" 396 + fill-rule="evenodd" 397 + stroke-linejoin="round" 398 + stroke-miterlimit="2" 399 + width="18" 400 + height="18" 401 + fill="currentColor" 402 + viewBox="0 0 24 24" 403 + xmlns="http://www.w3.org/2000/svg" 404 + ><path 405 + d="m10.211 7.155c-.141-.108-.3-.157-.456-.157-.389 0-.755.306-.755.749v8.501c0 .445.367.75.755.75.157 0 .316-.05.457-.159 1.554-1.203 4.199-3.252 5.498-4.258.184-.142.29-.36.29-.592 0-.23-.107-.449-.291-.591-1.299-1.002-3.945-3.044-5.498-4.243z" 406 + /></svg 407 + > 408 + </div> 409 + </div> 410 + {/if} 411 + </div> 412 + <div class="text"> 413 + <div class="name">{name}</div> 414 + <div class="artist">{artist}</div> 415 + </div> 394 416 </div> 395 - <div class="text"> 396 - <div class="name">{name}</div> 397 - <div class="artist">{artist}</div> 417 + <div class="spacer" /> 418 + <div class="row"> 419 + <div class="label">Title</div> 420 + <!-- svelte-ignore a11y-autofocus --> 421 + <input type="text" bind:value={name} autofocus /> 398 422 </div> 399 - </div> 400 - <div class="spacer" /> 401 - <div class="row"> 402 - <div class="label">Title</div> 403 - <!-- svelte-ignore a11y-autofocus --> 404 - <input type="text" bind:value={name} autofocus /> 405 - </div> 406 - <div class="row"> 407 - <div class="label">Artist</div> 408 - <input type="text" bind:value={artist} /> 409 - </div> 410 - <div class="row"> 411 - <div class="label">Album</div> 412 - <input type="text" bind:value={album_name} /> 413 - </div> 414 - <div class="row"> 415 - <div class="label">Album artist</div> 416 - <input type="text" bind:value={album_artist} /> 417 - </div> 418 - <div class="row"> 419 - <div class="label">Composer</div> 420 - <input type="text" bind:value={composer} /> 421 - </div> 422 - <div class="row"> 423 - <div class="label">Grouping</div> 424 - <input type="text" bind:value={grouping} /> 425 - </div> 426 - <div class="row"> 427 - <div class="label">Genre</div> 428 - <input type="text" bind:value={genre} /> 429 - </div> 430 - <div class="row"> 431 - <div class="label">Year</div> 432 - <input class="medium" type="text" bind:value={year} /> 433 - </div> 434 - <div class="row num"> 435 - <div class="label">Track</div> 436 - <input class="num" type="text" bind:value={track_num} class:big={big(track_num)} /> 437 - <div class="midtext">of</div> 438 - <input class="num" type="text" bind:value={track_count} class:big={big(track_count)} /> 439 - </div> 440 - <div class="row num"> 441 - <div class="label">Disc number</div> 442 - <input class="num" type="text" bind:value={disc_num} class:big={big(disc_num)} /> 443 - <div class="midtext">of</div> 444 - <input class="num" type="text" bind:value={disc_count} class:big={big(disc_count)} /> 445 - </div> 446 - <div class="row"> 447 - <div class="label">Compilation</div> 448 - <p>{compilation ? 'Yes' : 'No'}</p> 449 - </div> 450 - <div class="row"> 451 - <div class="label">Rating</div> 452 - <p>{rating}, {liked ? 'Liked' : 'Not Liked'}</p> 453 - </div> 454 - <div class="row"> 455 - <div class="label">BPM</div> 456 - <input class="medium" type="text" bind:value={bpm} /> 457 - </div> 458 - <div class="row"> 459 - <div class="label">Play count</div> 460 - <p>{play_count}</p> 461 - </div> 462 - <div class="row"> 463 - <div class="label">Comments</div> 464 - <input type="text" bind:value={comments} /> 465 - </div> 466 - <div class="spacer" /> 467 - </main> 468 - <svelte:fragment slot="buttons"> 469 - <Button secondary on:click={cancel}>Cancel</Button> 470 - <Button type="submit" on:click={() => save()}>Save</Button> 471 - </svelte:fragment> 472 - </Modal> 423 + <div class="row"> 424 + <div class="label">Artist</div> 425 + <input type="text" bind:value={artist} /> 426 + </div> 427 + <div class="row"> 428 + <div class="label">Album</div> 429 + <input type="text" bind:value={album_name} /> 430 + </div> 431 + <div class="row"> 432 + <div class="label">Album artist</div> 433 + <input type="text" bind:value={album_artist} /> 434 + </div> 435 + <div class="row"> 436 + <div class="label">Composer</div> 437 + <input type="text" bind:value={composer} /> 438 + </div> 439 + <div class="row"> 440 + <div class="label">Grouping</div> 441 + <input type="text" bind:value={grouping} /> 442 + </div> 443 + <div class="row"> 444 + <div class="label">Genre</div> 445 + <input type="text" bind:value={genre} /> 446 + </div> 447 + <div class="row"> 448 + <div class="label">Year</div> 449 + <input class="medium" type="text" bind:value={year} /> 450 + </div> 451 + <div class="row num"> 452 + <div class="label">Track</div> 453 + <input class="num" type="text" bind:value={track_num} class:big={big(track_num)} /> 454 + <div class="midtext">of</div> 455 + <input class="num" type="text" bind:value={track_count} class:big={big(track_count)} /> 456 + </div> 457 + <div class="row num"> 458 + <div class="label">Disc number</div> 459 + <input class="num" type="text" bind:value={disc_num} class:big={big(disc_num)} /> 460 + <div class="midtext">of</div> 461 + <input class="num" type="text" bind:value={disc_count} class:big={big(disc_count)} /> 462 + </div> 463 + <div class="row"> 464 + <div class="label">Compilation</div> 465 + <p>{compilation ? 'Yes' : 'No'}</p> 466 + </div> 467 + <div class="row"> 468 + <div class="label">Rating</div> 469 + <p>{rating}, {liked ? 'Liked' : 'Not Liked'}</p> 470 + </div> 471 + <div class="row"> 472 + <div class="label">BPM</div> 473 + <input class="medium" type="text" bind:value={bpm} /> 474 + </div> 475 + <div class="row"> 476 + <div class="label">Play count</div> 477 + <p>{play_count}</p> 478 + </div> 479 + <div class="row"> 480 + <div class="label">Comments</div> 481 + <input type="text" bind:value={comments} /> 482 + </div> 483 + <div class="spacer" /> 484 + </main> 485 + <svelte:fragment slot="buttons"> 486 + <Button secondary on:click={cancel}>Cancel</Button> 487 + <Button type="submit" on:click={() => save()}>Save</Button> 488 + </svelte:fragment> 489 + </Modal> 490 + {/if} 473 491 474 492 <style lang="sass"> 475 493 $cover-size: 90px
+2 -4
src/components/TrackList.svelte
··· 20 20 import { onDestroy, onMount } from 'svelte' 21 21 import { dragged } from '../lib/drag-drop' 22 22 import * as dragGhost from './DragGhost.svelte' 23 - import type { TrackID } from 'ferrum-addon/addon' 24 23 import VirtualListBlock, { scroll_container_keydown } from './VirtualListBlock.svelte' 25 - 26 - export let on_track_info: (allIds: TrackID[], index: number) => void 24 + import { open_track_info } from './TrackInfo.svelte' 27 25 28 26 let tracklist_element: HTMLDivElement 29 27 ··· 39 37 const ids = selection.getSelectedIndexes().map((i) => page.get_track_id(i)) 40 38 append_to_user_queue(ids) 41 39 } else if (action === 'Get Info') { 42 - on_track_info(page.get_track_ids(), first_index) 40 + open_track_info(page.get_track_ids(), first_index) 43 41 } else if (action === 'revealTrackFile') { 44 42 const track = page.get_track(first_index) 45 43 ipc_renderer.invoke('revealTrackFile', paths.tracksDir, track.file)