diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 33d86689..06372e62 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -36,16 +36,16 @@ jobs: env: GH_TOKEN: ${{ secrets.GH_TOKEN }} - release-macos: - if: ${{ github.event.workflow_run.conclusion == 'success' }} - runs-on: macos-latest + release-macos: + if: ${{ github.event.workflow_run.conclusion == 'success' }} + runs-on: macos-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 - with: - node-version: 14.x - - run: npm ci - - run: npm run release:publish -- onTagOrDraft -m - env: - GH_TOKEN: ${{ secrets.GH_TOKEN }} + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: 14.x + - run: npm ci + - run: npm run release:publish -- onTagOrDraft -m + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} diff --git a/README.md b/README.md index 1415165b..f094f371 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,9 @@ There are thunsands of them in the wild. This mine is an excuse for learning [El ### features -- [ ] feedback when adding to playlist - [ ] images from tags - [ ] system integration (play folder/file) - [ ] display album/artist descriptions -- [ ] enqueue tracks/albums by dragging to tracks queue - [ ] configure replay gain from settings - [ ] display tracks/albums/artists count in settings - [ ] allow reseting database from settings diff --git a/locale/en.yml b/locale/en.yml index 2b519327..2e6a7503 100644 --- a/locale/en.yml +++ b/locale/en.yml @@ -53,6 +53,7 @@ no: No no clear during tutorial: It is not possible to clear the queue during this tutorial no results: Nothing at all ! on unsplash: on Unsplash. +open: Open open folder: Open containing folder open queue: Open queue play all: Play all @@ -60,6 +61,7 @@ play now: Play now play now behaviour: 'Button play_arrow:' playlist deletion: Playlist deletion playlist renamal: Playlist new name +playlist _ updated: Playlist "{ name }" updated! playlists: Playlists plays track: plays track photos by: 'Photos by:' diff --git a/locale/fr.yml b/locale/fr.yml index b6dfbc23..2a60f33d 100644 --- a/locale/fr.yml +++ b/locale/fr.yml @@ -41,6 +41,7 @@ no: Non no clear during tutorial: Il n'est pas possible de vider la liste pendant la présentation no results: Rien du tout ! on unsplash: sur Unsplash. +open: Ouvrir open folder: Ouvrir le dossier parent open queue: Liste de lecture play all: Lire tout @@ -48,6 +49,7 @@ play now: Lire maintenant play now behaviour: 'Le bouton play_arrow :' playlist deletion: Suppression de la playlist playlist renamal: Nouveau nom pour la playlist +playlist _ updated: Playlist "{ name }" enregistrée ! plays track: lit le morceau photos by: 'Photos par :' queue: Liste de lecture diff --git a/renderer/components/Dialogue/Dialogue.svelte b/renderer/components/Dialogue/Dialogue.svelte index 3d3f2580..ed785a50 100644 --- a/renderer/components/Dialogue/Dialogue.svelte +++ b/renderer/components/Dialogue/Dialogue.svelte @@ -48,7 +48,7 @@ } article { - @apply flex flex-col; + @apply flex flex-col text-center; width: 50%; max-height: 80%; } diff --git a/renderer/stores/playlists.js b/renderer/stores/playlists.js index 188cbfcd..87833c87 100644 --- a/renderer/stores/playlists.js +++ b/renderer/stores/playlists.js @@ -1,6 +1,9 @@ 'use strict' +import { push } from 'svelte-spa-router' +import { showSnack } from './snackbars' import { createListStore, invoke } from '../utils' +import * as intl from 'svelte-intl' const store = createListStore('playlist') @@ -12,6 +15,9 @@ export const changes = store.changes export const removals = store.removals export const isListing = store.isListing +let translate +intl.translate.subscribe(_ => (translate = _)) + export async function remove({ id }) { return save({ id, trackIds: [] }) } @@ -21,9 +27,17 @@ export async function appendTracks({ id, name, tracks }) { if (!trackIds.length) { return null } - return id + const playlist = await (id ? invoke('playlists.append', id, trackIds) - : save({ name, trackIds }) + : save({ name, trackIds })) + showSnack({ + message: translate('playlist _ updated', playlist), + button: translate('open'), + action() { + push(`/playlist/${playlist.id}`) + } + }) + return playlist } export async function removeTrack(playlist, index) { diff --git a/renderer/stores/playlists.test.js b/renderer/stores/playlists.test.js index dcee10da..af4ff4fb 100644 --- a/renderer/stores/playlists.test.js +++ b/renderer/stores/playlists.test.js @@ -11,10 +11,14 @@ import { moveTrack, isListing } from './playlists' -import { mockInvoke, sleep } from '../tests' +import { clear, current } from './snackbars' +import { mockInvoke, sleep, translate } from '../tests' describe('playlists store', () => { - beforeEach(jest.clearAllMocks) + beforeEach(() => { + jest.clearAllMocks() + clear() + }) it('lists all playlists', async () => { const total = 13 @@ -51,6 +55,7 @@ describe('playlists store', () => { const id = faker.random.number() expect(await appendTracks({ id, tracks: [] })).toEqual(null) expect(mockInvoke).not.toHaveBeenCalled() + expect(get(current)).toBeNil() }) it('appends tracks to existing playlist', async () => { @@ -73,6 +78,12 @@ describe('playlists store', () => { trackIds ) expect(mockInvoke).toHaveBeenCalledTimes(1) + await sleep() + expect(get(current)).toEqual({ + message: translate('playlist _ updated', playlist), + action: expect.any(Function), + button: translate('open') + }) }) it('creates new playlist with tracks', async () => { @@ -92,6 +103,12 @@ describe('playlists store', () => { trackIds }) expect(mockInvoke).toHaveBeenCalledTimes(1) + await sleep() + expect(get(current)).toEqual({ + message: translate('playlist _ updated', playlist), + action: expect.any(Function), + button: translate('open') + }) }) }) @@ -118,6 +135,7 @@ describe('playlists store', () => { ] }) expect(mockInvoke).toHaveBeenCalledTimes(1) + expect(get(current)).toBeNil() }) it('ignores invalid indices', async () => { @@ -169,6 +187,7 @@ describe('playlists store', () => { trackIds: [2, 3, 1, 4] }) expect(mockInvoke).toHaveBeenCalledTimes(1) + expect(get(current)).toBeNil() }) it('move tracks backward', async () => { @@ -188,6 +207,7 @@ describe('playlists store', () => { { ...playlist, trackIds: [1, 4, 2, 3] } ) expect(mockInvoke).toHaveBeenCalledTimes(1) + expect(get(current)).toBeNil() }) it('ignores invalid indices', async () => { @@ -252,6 +272,7 @@ describe('playlists store', () => { trackIds: [] }) expect(mockInvoke).toHaveBeenCalledTimes(1) + expect(get(current)).toBeNil() }) }) }) diff --git a/renderer/stores/snackbars.js b/renderer/stores/snackbars.js index 37a406d4..2a11d5f8 100644 --- a/renderer/stores/snackbars.js +++ b/renderer/stores/snackbars.js @@ -1,7 +1,7 @@ 'use strict' import { Subject } from 'rxjs' -import { map, scan } from 'rxjs/operators' +import { map, scan, shareReplay } from 'rxjs/operators' const queue$ = new Subject() const head$ = new Subject() @@ -41,7 +41,8 @@ export const current = head$.pipe( setTimeout(() => head$.next({ data }), 0) } return null - }) + }), + shareReplay() ) export function showSnack(data, duration = 5000) {