mirror of
https://github.com/heyarne/airsonic-ui.git
synced 2026-05-06 18:33:38 +02:00
Show current queue (closes #23)
commit 77d9068b8ced163d89d280f0e4ea40f3a55a831d
Author: Arne Schlüter <arne@schlueter.is>
Date: Mon Oct 8 23:49:49 2018 +0200
Mark current track everywhere in app
commit 6243f87b3bdf64b27afeae5007386d4a7fe32fea
Author: Arne Schlüter <arne@schlueter.is>
Date: Mon Oct 8 23:33:07 2018 +0200
s/currently playing/current queue/, move link to own button and add about page
commit 1dfb00b0623f64ae32953f112192894008c6adc9
Author: Arne Schlüter <arne@schlueter.is>
Date: Mon Oct 8 22:32:11 2018 +0200
Implement simple "currently playing" page
commit a2fef45a8a8989e1d176d859c875d994982f7329
Author: Arne Schlüter <arne@schlueter.is>
Date: Mon Oct 8 22:00:37 2018 +0200
Hide unimplemented / incomplete features from navbar and add 404 page
This commit is contained in:
parent
fa485bbf42
commit
b5763ca4a5
9 changed files with 112 additions and 41 deletions
16
src/cljs/airsonic_ui/components/about/views.cljs
Normal file
16
src/cljs/airsonic_ui/components/about/views.cljs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
(ns airsonic-ui.components.about.views)
|
||||
|
||||
(defn about []
|
||||
[:section.section>div.container.content
|
||||
[:h1 "About"]
|
||||
[:p "This is a frontend for " [:a {:href "https://airsonic.github.io/"
|
||||
:target "_blank"} "airsonic"] ", a free and open source media server. You can think of airsonic as a Spotify that you can run out of a shoebox in your bedroom, enabling you to listen to your own music wherever you are."]
|
||||
[:h2 "Motivation"]
|
||||
[:p "The current frontend of airsonic has been written quite a long time ago - eons on a web-development timescale, where the clocks tick a bit different. While it has many features it has unfortunately aged noticeably. It does not work well on mobile and some features, such as sharing parts of your music library, require Adobe Flash, leaving them practically unusable and insecure."]
|
||||
[:p "This fronted aims to provide a focused subset. Its focus for now is on playing and sharing music. Setting up the airsonic instance has to be done via the old interface, as does podcast management."]
|
||||
[:h2 "Contact"]
|
||||
[:p "The airsonic community can be found on " [:a {:href "https://riot.im/app/#/room/#airsonic:matrix.org"
|
||||
:target "_blank"} "Matrix"]
|
||||
" and IRC (#airsonic on freenode). There is also a " [:a {:href "https://www.reddit.com/r/airsonic/"
|
||||
:target "_blank"} "dedicated Subreddit"] ". If you think you found bugs in the frontend, it's probably a good idea to " [:a {:href "https://github.com/heyarne/airsonic-ui/issues"
|
||||
:target "_blank"} "report them on github"] ". I hope you have fun with the software! If you want to say thanks or have a use case that you feel could be covered, feel free to get in touch. Just know that everybody involved does this in their free time."]])
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
(ns airsonic-ui.components.audio-player.views
|
||||
(:require [re-frame.core :refer [subscribe]]
|
||||
[airsonic-ui.routes :as routes]
|
||||
[airsonic-ui.helpers :refer [add-classes muted-dispatch]]
|
||||
[airsonic-ui.views.cover :refer [cover]]
|
||||
[airsonic-ui.views.icon :refer [icon]]))
|
||||
|
|
@ -7,8 +8,8 @@
|
|||
;; currently playing / coming next / audio controls...
|
||||
|
||||
(defn current-song-info [song status]
|
||||
[:article
|
||||
[:div (:artist song) " - " (:title song)]
|
||||
[:article.current-song-info
|
||||
[:span (:artist song) " - " (:title song)]
|
||||
;; FIXME: Sometimes items don't have a duration
|
||||
[:progress.progress.is-tiny {:value (:current-time status)
|
||||
:max (:duration song)}]])
|
||||
|
|
@ -17,10 +18,15 @@
|
|||
[:div.field.has-addons
|
||||
(let [buttons [[:media-step-backward :audio-player/previous-song]
|
||||
[(if is-playing? :media-pause :media-play) :audio-player/toggle-play-pause]
|
||||
[:media-step-forward :audio-player/next-song]]]
|
||||
[:media-step-forward :audio-player/next-song]]
|
||||
title {:media-step-backward "Previous"
|
||||
:media-play "Play"
|
||||
:media-pause "Pause"
|
||||
:media-step-forward "Next"}]
|
||||
(map (fn [[icon-glyph event]]
|
||||
^{:key icon-glyph} [:p.control>button.button.is-light
|
||||
{:on-click (muted-dispatch [event])}
|
||||
{:on-click (muted-dispatch [event])
|
||||
:title (title icon-glyph)}
|
||||
[icon icon-glyph]])
|
||||
buttons))])
|
||||
|
||||
|
|
@ -41,10 +47,16 @@
|
|||
repeat-button (add-classes button (case repeat-mode
|
||||
:repeat-single :is-info
|
||||
:repeat-all :is-primary
|
||||
nil))]
|
||||
nil))
|
||||
repeat-title (case repeat-mode
|
||||
:repeat-all "Click to repeat current track"
|
||||
:repeat-single "Click to repeat all"
|
||||
"Click to repeat current track")]
|
||||
[:div.field.has-addons
|
||||
^{:key :shuffle-button} [shuffle-button {:on-click (toggle-shuffle playback-mode)} [icon :random]]
|
||||
^{:key :repeat-button} [repeat-button {:on-click (toggle-repeat-mode repeat-mode)} [icon :loop]]]))
|
||||
^{:key :shuffle-button} [shuffle-button {:on-click (toggle-shuffle playback-mode)
|
||||
:title "Shuffle"} [icon :random]]
|
||||
^{:key :repeat-button} [repeat-button {:on-click (toggle-repeat-mode repeat-mode)
|
||||
:title repeat-title} [icon :loop]]]))
|
||||
|
||||
(defn audio-player []
|
||||
(let [current-song @(subscribe [:audio/current-song])
|
||||
|
|
@ -60,7 +72,8 @@
|
|||
[:div.media-left [cover current-song 48]]
|
||||
[:div.media-content [current-song-info current-song playback-status]]]
|
||||
[:div.level-right
|
||||
[:div.buttons-start [song-controls is-playing?]]
|
||||
[:div.buttons-end [playback-mode-controls playlist]]]]
|
||||
[:div.button-group [:p.control>a.button.is-light {:href (routes/url-for ::routes/current-queue) :title "Go to current queue"} [icon :menu]]]
|
||||
[:div.button-group [song-controls is-playing?]]
|
||||
[:div.button-group [playback-mode-controls playlist]]]]
|
||||
;; not playing anything
|
||||
[:p.navbar-item.idle-notification "No audio playing"])]]))
|
||||
|
|
|
|||
10
src/cljs/airsonic_ui/components/bangpow/views.cljs
Normal file
10
src/cljs/airsonic_ui/components/bangpow/views.cljs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
(ns airsonic-ui.components.bangpow.views)
|
||||
|
||||
(defn not-found []
|
||||
[:section.section>div.container.content
|
||||
[:h1 "Oooops..."]
|
||||
[:p "That should not have happened. There are multiple things that might have gone wrong:"]
|
||||
[:ul
|
||||
[:li "You clicked a wrong link. Maybe you copy and pasted it and missed something."]
|
||||
[:li "It's a bug in the user interface. In that case: sorry! You can report it " [:a {:href "https://github.com/heyarne/airsonic-ui/issues"
|
||||
:target "_blank"} "on github"]"."]]])
|
||||
12
src/cljs/airsonic_ui/components/current_queue/views.cljs
Normal file
12
src/cljs/airsonic_ui/components/current_queue/views.cljs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
(ns airsonic-ui.components.current-queue.views
|
||||
(:require [re-frame.core :refer [subscribe]]
|
||||
[airsonic-ui.views.song :as song]
|
||||
[airsonic-ui.routes :as r]))
|
||||
|
||||
(defn current-queue []
|
||||
[:section.section>div.container
|
||||
[:h1.title "Current Queue"]
|
||||
(if-let [playlist @(subscribe [:audio/playlist])]
|
||||
[song/listing (:queue playlist)]
|
||||
[:p "You are currently not playing anything. Use the search or go to your "
|
||||
[:a {:href (r/url-for ::r/library)} "Library"] " to start playing some music."])])
|
||||
|
|
@ -3,8 +3,7 @@
|
|||
[ajax.core :as ajax]
|
||||
[airsonic-ui.routes :as routes]
|
||||
[airsonic-ui.db :as db]
|
||||
[airsonic-ui.api.helpers :as api]
|
||||
[airsonic-ui.audio.playlist :as playlist]))
|
||||
[airsonic-ui.api.helpers :as api]))
|
||||
|
||||
(re-frame/reg-fx
|
||||
;; a simple effect to keep println statements out of our event handlers
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@
|
|||
["/album/:id" ::album.detail]
|
||||
["/search" ::search]
|
||||
["/podcast" ::podcast.overview]
|
||||
["/podcast/:id" ::podcast.detail]]))
|
||||
["/podcast/:id" ::podcast.detail]
|
||||
["/current-queue" ::current-queue]
|
||||
["/about" ::about]]))
|
||||
|
||||
;; use this in views to construct a url
|
||||
(defn url-for
|
||||
|
|
|
|||
|
|
@ -11,12 +11,17 @@
|
|||
[airsonic-ui.views.notifications :refer [notification-list]]
|
||||
[airsonic-ui.views.breadcrumbs :refer [breadcrumbs]]
|
||||
[airsonic-ui.views.login :refer [login-form]]
|
||||
[airsonic-ui.components.audio-player.views :refer [audio-player]]
|
||||
[airsonic-ui.components.search.views :as search]
|
||||
[airsonic-ui.components.library.views :as library]
|
||||
[airsonic-ui.views.icon :refer [icon]]
|
||||
|
||||
[airsonic-ui.components.about.views :refer [about]]
|
||||
[airsonic-ui.components.artist.views :as artist]
|
||||
[airsonic-ui.components.audio-player.views :refer [audio-player]]
|
||||
[airsonic-ui.components.bangpow.views :refer [not-found]]
|
||||
[airsonic-ui.components.collection.views :as collection]
|
||||
[airsonic-ui.components.podcast.views :as podcast]))
|
||||
[airsonic-ui.components.current-queue.views :refer [current-queue]]
|
||||
[airsonic-ui.components.library.views :as library]
|
||||
[airsonic-ui.components.podcast.views :as podcast]
|
||||
[airsonic-ui.components.search.views :as search]))
|
||||
|
||||
(def logo-url "./img/airsonic-light-350x100.png")
|
||||
|
||||
|
|
@ -62,24 +67,27 @@
|
|||
[:div.navbar-start
|
||||
[:div.navbar-item [search/form]]]
|
||||
[:div.navbar-end
|
||||
[:a.navbar-item {:href (url-for ::routes/current-queue)
|
||||
:title "Current queue"} [icon :audio]]
|
||||
(when stream-role
|
||||
[navbar-dropdown "Library"
|
||||
[[{:href (url-for ::routes/library {:criteria "recent"})} "Recently played"]
|
||||
[{:href (url-for ::routes/library {:criteria "newest"})} "Newest additions"]
|
||||
[{:href (url-for ::routes/library {:criteria "starred"})} "Starred"]]])
|
||||
(when podcast-role
|
||||
(let [podcast-url (url-for ::routes/podcast.overview)]
|
||||
#_(let [podcast-url (url-for ::routes/podcast.overview)]
|
||||
[navbar-dropdown "Podcast" {:href podcast-url}
|
||||
[[{:href podcast-url} "Overview"]]]))
|
||||
(when playlist-role
|
||||
[navbar-item {} "Playlists"])
|
||||
#_[navbar-item {} "Playlists"])
|
||||
(when share-role
|
||||
[navbar-item {} "Shares"])
|
||||
#_[navbar-item {} "Shares"])
|
||||
[:div.navbar-item.has-dropdown.is-hoverable
|
||||
[:div.navbar-link "More"]
|
||||
[:div.navbar-dropdown.is-right
|
||||
(when settings-role
|
||||
[navbar-item {} "Settings"])
|
||||
#_[navbar-item {} "Settings"])
|
||||
[:a.navbar-item {:href (url-for ::routes/about)} "About"]
|
||||
[:a.navbar-item
|
||||
{:on-click (fn [_]
|
||||
(toggle-navbar-active!)
|
||||
|
|
@ -107,7 +115,10 @@
|
|||
::routes/album.detail [collection/detail content]
|
||||
::routes/search [search/results content]
|
||||
::routes/podcast.overview [podcast/overview content]
|
||||
::routes/podcast.detail [podcast/detail content])]
|
||||
::routes/podcast.detail [podcast/detail content]
|
||||
::routes/current-queue [current-queue]
|
||||
::routes/about [about]
|
||||
[not-found])]
|
||||
[audio-player]]))
|
||||
|
||||
(defn main-panel
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
(ns airsonic-ui.views.song
|
||||
(:require [airsonic-ui.helpers :refer [muted-dispatch]]
|
||||
(:require [re-frame.core :refer [subscribe]]
|
||||
[airsonic-ui.helpers :refer [muted-dispatch]]
|
||||
[airsonic-ui.routes :as routes :refer [url-for]]
|
||||
[airsonic-ui.views.icon :refer [icon]]))
|
||||
|
||||
|
|
@ -15,15 +16,17 @@
|
|||
(:title song)]]))
|
||||
|
||||
(defn listing [songs]
|
||||
[:table.table.is-striped.is-hoverable.is-fullwidth.song-list>tbody
|
||||
(for [[idx song] (map-indexed vector songs)]
|
||||
^{:key idx} [:tr
|
||||
[:td.grow [item songs song idx]]
|
||||
[:td>a {:title "Play next"
|
||||
:href "#"
|
||||
:on-click (muted-dispatch [:audio-player/enqueue-next song])}
|
||||
[icon :plus]]
|
||||
[:td>a {:title "Play last"
|
||||
:href "#"
|
||||
:on-click (muted-dispatch [:audio-player/enqueue-last song])}
|
||||
[icon :caret-right]]])])
|
||||
(let [current-song @(subscribe [:audio/current-song])]
|
||||
[:table.table.is-striped.is-hoverable.is-fullwidth.song-list>tbody
|
||||
(for [[idx song] (map-indexed vector songs)]
|
||||
(let [tag (if (= (:id song) (:id current-song)) :tr.song.is-playing :tr.song)]
|
||||
^{:key idx} [tag
|
||||
[:td.grow [item songs song idx]]
|
||||
[:td>a {:title "Play next"
|
||||
:href "#"
|
||||
:on-click (muted-dispatch [:audio-player/enqueue-next song])}
|
||||
[icon :plus]]
|
||||
[:td>a {:title "Play last"
|
||||
:href "#"
|
||||
:on-click (muted-dispatch [:audio-player/enqueue-last song])}
|
||||
[icon :caret-right]]]))]))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue