diff --git a/src/cljs/airsonic_ui/audio/playlist.cljs b/src/cljs/airsonic_ui/audio/playlist.cljs index 0cc374a..5a8d720 100644 --- a/src/cljs/airsonic_ui/audio/playlist.cljs +++ b/src/cljs/airsonic_ui/audio/playlist.cljs @@ -48,9 +48,13 @@ (defrecord Playlist [items current-idx playback-mode repeat-mode] cljs.core/ICounted - (-count [this] + (-count [_] (count items)) + cljs.core/ISequential + cljs.core/ISeqable + (-seq [_] items) + IPlaylist (current-song [_] (get items current-idx)) diff --git a/src/cljs/airsonic_ui/components/audio_player/events.cljs b/src/cljs/airsonic_ui/components/audio_player/events.cljs index 3fe5e44..0ddff43 100644 --- a/src/cljs/airsonic_ui/components/audio_player/events.cljs +++ b/src/cljs/airsonic_ui/components/audio_player/events.cljs @@ -34,9 +34,17 @@ :audio-player/previous-song (fn [{:keys [db]} _] (let [db (update-in db [:audio :current-playlist] playlist/previous-song) - prev (playlist/current-song (get-in db [:audio :current-playlist]))] + song (playlist/current-song (get-in db [:audio :current-playlist]))] {:db db - :audio/play (api/stream-url (:credentials db) prev)}))) + :audio/play (api/stream-url (:credentials db) song)}))) + +(defn set-current-song [{:keys [db]} [_ idx]] + (let [db (update-in db [:audio :current-playlist] playlist/set-current-song idx) + song (playlist/current-song (get-in db [:audio :current-playlist]))] + {:db db + :audio/play (api/stream-url (:credentials db) song)})) + +(rf/reg-event-fx :audio-player/set-current-song set-current-song) (rf/reg-event-db :audio-player/enqueue-next diff --git a/src/cljs/airsonic_ui/components/current_queue/views.cljs b/src/cljs/airsonic_ui/components/current_queue/views.cljs index 1744561..91b0edf 100644 --- a/src/cljs/airsonic_ui/components/current_queue/views.cljs +++ b/src/cljs/airsonic_ui/components/current_queue/views.cljs @@ -3,7 +3,6 @@ [reagent.core :as r] ["react-sortable-hoc" :refer [SortableHandle]] [airsonic-ui.helpers :as helpers] - [airsonic-ui.views.song :as song] [airsonic-ui.views.icon :refer [icon]] [airsonic-ui.components.sortable.views :as sortable] [airsonic-ui.routes :as routes])) @@ -39,6 +38,12 @@ [:a {:href (routes/url-for ::routes/artist.detail {:id id})} artist] artist)) +(defn song-link [song idx] + [:a + {:href "#" + :on-click (helpers/muted-dispatch [:audio-player/set-current-song idx])} + (:title song)]) + (defn song-table [{:keys [songs current-song]}] [:table.song-listing-table.table.is-fullwidth [sortable/sortable-component @@ -46,12 +51,11 @@ :items songs :render-item - (fn [{song :value}] + (fn [{[idx song] :value}] [(if (= (:id song) (:id current-song)) :tr.is-playing :tr) [:td.sort-handle.is-narrow [:> SortHandle]] [:td.song-artist [artist-link song]] - [:td.song-title (:title song)] - [:td.meta>code (str (meta song))] + [:td.song-title [song-link song idx]] [:td.song-duration (helpers/format-duration (:duration song) :brief? true)] [:td.song-actions.is-narrow [song-actions]]]) @@ -62,10 +66,10 @@ (defn current-queue [] [:section.section>div.container [:h1.title "Current Queue"] - (let [current-queue @(subscribe [:audio/current-queue]) + (let [current-playlist @(subscribe [:audio/current-playlist]) current-song @(subscribe [:audio/current-song])] - (if (some? current-queue) - [song-table {:songs current-queue - :current-song current-song}] + (if (empty? current-playlist) [:p "You are currently not playing anything. Use the search or go to your " - [:a {:href (routes/url-for ::routes/library)} "Library"] " to start playing some music."]))]) + [:a {:href (routes/url-for ::routes/library)} "Library"] " to start playing some music."] + [song-table {:songs (:items current-playlist) + :current-song current-song}]))]) diff --git a/test/cljs/airsonic_ui/audio/playlist_test.cljs b/test/cljs/airsonic_ui/audio/playlist_test.cljs index b9d4a41..0f50127 100644 --- a/test/cljs/airsonic_ui/audio/playlist_test.cljs +++ b/test/cljs/airsonic_ui/audio/playlist_test.cljs @@ -2,27 +2,11 @@ (:require [cljs.test :refer [deftest testing is]] [airsonic-ui.audio.playlist :as playlist] [airsonic-ui.fixtures :as fixtures] - [airsonic-ui.test-helpers :as helpers] - [debux.cs.core :refer-macros [dbg]])) + [airsonic-ui.test-helpers :refer [song song-queue]] + #_[debux.cs.core :refer-macros [dbg]])) (enable-console-print!) -(defn- song [] - (hash-map :id (rand-int 9999) - :coverArt (rand-int 9999) - :year (+ 1900 (rand-int 118)) - :artist (helpers/rand-str) - :artistId (rand-int 100000) - :title (helpers/rand-str) - :album (helpers/rand-str))) - -(defn- song-queue - "Generates a seq of n different songs" - [n] - (let [r-int (atom 0)] - (with-redefs [rand-int #(mod (swap! r-int inc) %1)] - (repeatedly n song)))) - (def fixture {:audio {:current-song fixtures/song :playlist (song-queue 20) diff --git a/test/cljs/airsonic_ui/components/audio_player/events_test.cljs b/test/cljs/airsonic_ui/components/audio_player/events_test.cljs index 4225bc3..9ca8e9f 100644 --- a/test/cljs/airsonic_ui/components/audio_player/events_test.cljs +++ b/test/cljs/airsonic_ui/components/audio_player/events_test.cljs @@ -1,10 +1,29 @@ (ns airsonic-ui.components.audio-player.events-test (:require [cljs.test :refer-macros [deftest testing is]] - [airsonic-ui.test-helpers :refer [dispatches?]] + [airsonic-ui.audio.core :as audio] + [airsonic-ui.audio.playlist :as playlist] + [airsonic-ui.fixtures :as fixtures] + [airsonic-ui.test-helpers :refer [dispatches? song-queue]] [airsonic-ui.components.audio-player.events :as events])) - (deftest song-has-ended (testing "Should play the next song when current song has ended" (is (not (dispatches? (events/audio-update {} [:audio/update {:ended? false}]) :audio-player/next-song))) (is (dispatches? (events/audio-update {} [:audio/update {:ended? true}]) :audio-player/next-song)))) + +(deftest changing-current-song + (testing "Should correctly set the current song index" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-single :repeat-all]] + (let [n-songs 100 + next-idx (rand-int n-songs) + fixture {:db {:credentials fixtures/credentials + :audio {:current-playlist (playlist/->playlist (song-queue n-songs) :playback-mode playback-mode :repeat-mode repeat-mode)}}} + effects (events/set-current-song fixture [:audio/set-current-song next-idx])] + (is (= next-idx + (-> (:db effects) + (audio/summary [:audio/summary]) + (audio/current-playlist [:audio/current-playlist]) + (:current-idx))) + (str "for playback-mode " playback-mode " and repeat-mode " repeat-mode)) + (is (contains? effects :audio/play)))))) diff --git a/test/cljs/airsonic_ui/test_helpers.cljs b/test/cljs/airsonic_ui/test_helpers.cljs index 1762f47..a03b67e 100644 --- a/test/cljs/airsonic_ui/test_helpers.cljs +++ b/test/cljs/airsonic_ui/test_helpers.cljs @@ -17,3 +17,19 @@ (from arr #(-> (str 0 (.toString % 16)) (.substr -2))) (join ""))))) + +(defn song [] + (hash-map :id (rand-int 9999) + :coverArt (rand-int 9999) + :year (+ 1900 (rand-int 118)) + :artist (rand-str) + :artistId (rand-int 100000) + :title (rand-str) + :album (rand-str))) + +(defn song-queue + "Generates a seq of n different songs" + [n] + (let [r-int (atom 0)] + (with-redefs [rand-int #(mod (swap! r-int inc) %1)] + (repeatedly n song))))