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) {