1
0
Fork 0
mirror of https://github.com/heyarne/airsonic-ui.git synced 2026-05-07 02:33:39 +02:00

Add duration text next to progress bar

This commit is contained in:
Arne Schlüter 2019-01-22 23:12:10 +01:00
commit 700a00aa56
4 changed files with 73 additions and 32 deletions

View file

@ -1,7 +1,7 @@
(ns airsonic-ui.components.audio-player.views (ns airsonic-ui.components.audio-player.views
(:require [re-frame.core :refer [subscribe dispatch]] (:require [re-frame.core :refer [subscribe dispatch]]
[airsonic-ui.routes :as routes] [airsonic-ui.routes :as routes]
[airsonic-ui.helpers :refer [add-classes muted-dispatch]] [airsonic-ui.helpers :as h]
[airsonic-ui.views.cover :refer [cover]] [airsonic-ui.views.cover :refer [cover]]
[airsonic-ui.views.icon :refer [icon]])) [airsonic-ui.views.icon :refer [icon]]))
@ -17,18 +17,23 @@
(defn- ratio->width [ratio] (defn- ratio->width [ratio]
(str (.toFixed (* 100 ratio) 2) "%")) (str (.toFixed (* 100 ratio) 2) "%"))
(defn progress-bar [song status] (defn progress-indicators [song status]
(let [current-time (:current-time status) (let [current-time (:current-time status)
buffered (:buffered status) buffered (:buffered status)
duration (:duration song) duration (:duration song)
progress-text (str (h/format-duration current-time :brief? true)
" / "
(h/format-duration duration :brief? true))
buffered-width (ratio->width (/ buffered duration)) buffered-width (ratio->width (/ buffered duration))
played-width (ratio->width (/ current-time duration))] played-width (ratio->width (/ current-time duration))]
[:article.progress-bar {:aria-hidden "true"} [:article.progress-indicators {:aria-hidden "true"}
[:div.complete-song] [:div.progress-bars
[:div.buffered-part {:style {:width buffered-width} [:div.complete-song-bar]
[:div.buffered-part-bar {:style {:width buffered-width}
:on-click seek}] :on-click seek}]
[:div.played-back {:style {:width played-width}} [:div.played-back-bar {:style {:width played-width}}
[:div.played-back-knob]]])) [:div.played-back-knob]]]
[:div.progress-info-text.duration-text progress-text]]))
(defn playback-info [song status] (defn playback-info [song status]
[:a.playback-info.media [:a.playback-info.media
@ -52,25 +57,25 @@
:media-step-forward "Next"}] :media-step-forward "Next"}]
(for [[icon-glyph event] buttons] (for [[icon-glyph event] buttons]
^{:key icon-glyph} [:p.control [:button.button.is-light ^{:key icon-glyph} [:p.control [:button.button.is-light
{:on-click (muted-dispatch [event]) {:on-click (h/muted-dispatch [event])
:title (title icon-glyph)} :title (title icon-glyph)}
[icon icon-glyph]]]))]]) [icon icon-glyph]]]))]])
(defn- toggle-shuffle [playback-mode] (defn- toggle-shuffle [playback-mode]
(muted-dispatch [:audio-player/set-playback-mode (if (= playback-mode :shuffled) (h/muted-dispatch [:audio-player/set-playback-mode (if (= playback-mode :shuffled)
:linear :shuffled)])) :linear :shuffled)]))
(defn- toggle-repeat-mode [current-mode] (defn- toggle-repeat-mode [current-mode]
(let [modes (cycle '(:repeat-none :repeat-all :repeat-single)) (let [modes (cycle '(:repeat-none :repeat-all :repeat-single))
next-mode (->> (drop-while (partial not= current-mode) modes) next-mode (->> (drop-while (partial not= current-mode) modes)
(second))] (second))]
(muted-dispatch [:audio-player/set-repeat-mode next-mode]))) (h/muted-dispatch [:audio-player/set-repeat-mode next-mode])))
(defn playback-mode-controls [playlist] (defn playback-mode-controls [playlist]
(let [{:keys [repeat-mode playback-mode]} playlist (let [{:keys [repeat-mode playback-mode]} playlist
button :p.control>button.button.is-light button :p.control>button.button.is-light
shuffle-button (add-classes button (when (= playback-mode :shuffled) :is-primary)) shuffle-button (h/add-classes button (when (= playback-mode :shuffled) :is-primary))
repeat-button (add-classes button (case repeat-mode repeat-button (h/add-classes button (case repeat-mode
:repeat-single :is-info :repeat-single :is-info
:repeat-all :is-primary :repeat-all :is-primary
nil)) nil))
@ -96,7 +101,7 @@
;; show song info, controls, progress bar, etc. ;; show song info, controls, progress bar, etc.
[:section.audio-interaction [:section.audio-interaction
[playback-info current-song playback-status] [playback-info current-song playback-status]
[progress-bar current-song playback-status] [progress-indicators current-song playback-status]
[playback-controls is-playing?] [playback-controls is-playing?]
[playback-mode-controls playlist]] [playback-mode-controls playlist]]
;; not playing anything ;; not playing anything

View file

@ -1,7 +1,8 @@
(ns airsonic-ui.helpers (ns airsonic-ui.helpers
"Assorted helper functions" "Assorted helper functions"
(:require [re-frame.core :as rf] (:require [re-frame.core :as rf]
[clojure.string :as str])) [clojure.string :as str])
(:import [goog.string format]))
(defn find-where (defn find-where
"Returns the the first item in `coll` with its index for which `(p song)` "Returns the the first item in `coll` with its index for which `(p song)`
@ -35,11 +36,22 @@
(str/lower-case) (str/lower-case)
(keyword))) (keyword)))
(defn format-duration [seconds] (defn- brief-duration [hours minutes seconds]
(let [hours (quot seconds 3600) (str (when (> hours 0)
minutes (quot (rem seconds 3600) 60) (format "%02d:" hours))
seconds (rem seconds 60)] (format "%02d:%02d" minutes seconds)))
(-> (cond-> ""
(defn- long-duration [hours minutes seconds]
(str/trim
(cond-> ""
(> hours 0) (str hours "h ") (> hours 0) (str hours "h ")
(> minutes 0) (str minutes "m ")) (> minutes 0) (str minutes "m ")
(str seconds "s")))) (> seconds 0) (str seconds "s"))))
(defn format-duration [seconds & {:keys [brief?]}]
(let [hours (Math/round (quot seconds 3600))
minutes (Math/round (quot (rem seconds 3600) 60))
seconds (Math/round (rem seconds 60))]
(if brief?
(brief-duration hours minutes seconds)
(long-duration hours minutes seconds))))

View file

@ -64,19 +64,30 @@
overflow: hidden overflow: hidden
text-overflow: ellipsis text-overflow: ellipsis
.progress-bar .progress-indicators
// hide progress bar on mobile // hide progress bar on mobile
display: none display: none
+tablet +tablet
display: block display: flex
flex-grow: 3 flex-grow: 3
position: relative
height: 1rem height: 1rem
.complete-song, .progress-info-text
.buffered-part, color: whitesmoke
.played-back font-size: $size-7
flex-shrink: 0
flex-grow: 0
.progress-bars
margin-left: .6rem
margin-right: .6rem
position: relative
flex-grow: 1
.complete-song-bar,
.buffered-part-bar,
.played-back-bar
height: 1rem height: 1rem
position: absolute position: absolute
top: 0 top: 0
@ -90,19 +101,20 @@
position: relative position: relative
top: 50% top: 50%
.complete-song
.complete-song-bar
width: 100% width: 100%
&:after &:after
background: rgb(93,93,93) background: rgb(93,93,93)
.buffered-part .buffered-part-bar
cursor: pointer cursor: pointer
&:after &:after
background: rgb(143,143,143) background: rgb(143,143,143)
.played-back .played-back-bar
pointer-events: none pointer-events: none
&:after &:after

View file

@ -31,3 +31,15 @@
(is (= :hello-world (helpers/kebabify :HelloWorld))) (is (= :hello-world (helpers/kebabify :HelloWorld)))
(is (= :how-are-you (helpers/kebabify :howAreYou))) (is (= :how-are-you (helpers/kebabify :howAreYou)))
(is (= :foobar (helpers/kebabify :foobar))))) (is (= :foobar (helpers/kebabify :foobar)))))
(deftest format-duration
(testing "Should format hours, minutes and seconds"
(is (= "1h" (helpers/format-duration 3600)))
(is (= "59m" (helpers/format-duration (* 59 60))))
(is (= "1m" (helpers/format-duration 60)))
(is (= "5s" (helpers/format-duration 5))))
(testing "Should respect the :brief? option"
(is (= "01:00:00" (helpers/format-duration 3600 :brief? true)))
(is (= "59:00" (helpers/format-duration (* 59 60) :brief? true)))
(is (= "01:00" (helpers/format-duration 60 :brief? true)))
(is (= "00:05" (helpers/format-duration 5 :brief? true)))))