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:
parent
a9fbe5c741
commit
700a00aa56
4 changed files with 73 additions and 32 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)))))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue