From 700a00aa567588b73569523f627dd24a00a38052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20Schl=C3=BCter?= Date: Tue, 22 Jan 2019 23:12:10 +0100 Subject: [PATCH] Add duration text next to progress bar --- .../components/audio_player/views.cljs | 33 +++++++++++-------- src/cljs/airsonic_ui/helpers.cljs | 30 ++++++++++++----- src/sass/app.sass | 30 ++++++++++++----- test/cljs/airsonic_ui/helpers_test.cljs | 12 +++++++ 4 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/cljs/airsonic_ui/components/audio_player/views.cljs b/src/cljs/airsonic_ui/components/audio_player/views.cljs index 79d951b..f8d2c37 100644 --- a/src/cljs/airsonic_ui/components/audio_player/views.cljs +++ b/src/cljs/airsonic_ui/components/audio_player/views.cljs @@ -1,7 +1,7 @@ (ns airsonic-ui.components.audio-player.views (:require [re-frame.core :refer [subscribe dispatch]] [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.icon :refer [icon]])) @@ -17,18 +17,23 @@ (defn- ratio->width [ratio] (str (.toFixed (* 100 ratio) 2) "%")) -(defn progress-bar [song status] +(defn progress-indicators [song status] (let [current-time (:current-time status) buffered (:buffered status) 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)) played-width (ratio->width (/ current-time duration))] - [:article.progress-bar {:aria-hidden "true"} - [:div.complete-song] - [:div.buffered-part {:style {:width buffered-width} - :on-click seek}] - [:div.played-back {:style {:width played-width}} - [:div.played-back-knob]]])) + [:article.progress-indicators {:aria-hidden "true"} + [:div.progress-bars + [:div.complete-song-bar] + [:div.buffered-part-bar {:style {:width buffered-width} + :on-click seek}] + [:div.played-back-bar {:style {:width played-width}} + [:div.played-back-knob]]] + [:div.progress-info-text.duration-text progress-text]])) (defn playback-info [song status] [:a.playback-info.media @@ -52,25 +57,25 @@ :media-step-forward "Next"}] (for [[icon-glyph event] buttons] ^{:key icon-glyph} [:p.control [:button.button.is-light - {:on-click (muted-dispatch [event]) + {:on-click (h/muted-dispatch [event]) :title (title icon-glyph)} [icon icon-glyph]]]))]]) (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)])) (defn- toggle-repeat-mode [current-mode] (let [modes (cycle '(:repeat-none :repeat-all :repeat-single)) next-mode (->> (drop-while (partial not= current-mode) modes) (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] (let [{:keys [repeat-mode playback-mode]} playlist button :p.control>button.button.is-light - shuffle-button (add-classes button (when (= playback-mode :shuffled) :is-primary)) - repeat-button (add-classes button (case repeat-mode + shuffle-button (h/add-classes button (when (= playback-mode :shuffled) :is-primary)) + repeat-button (h/add-classes button (case repeat-mode :repeat-single :is-info :repeat-all :is-primary nil)) @@ -96,7 +101,7 @@ ;; show song info, controls, progress bar, etc. [:section.audio-interaction [playback-info current-song playback-status] - [progress-bar current-song playback-status] + [progress-indicators current-song playback-status] [playback-controls is-playing?] [playback-mode-controls playlist]] ;; not playing anything diff --git a/src/cljs/airsonic_ui/helpers.cljs b/src/cljs/airsonic_ui/helpers.cljs index 046801c..6ed4015 100644 --- a/src/cljs/airsonic_ui/helpers.cljs +++ b/src/cljs/airsonic_ui/helpers.cljs @@ -1,7 +1,8 @@ (ns airsonic-ui.helpers "Assorted helper functions" (:require [re-frame.core :as rf] - [clojure.string :as str])) + [clojure.string :as str]) + (:import [goog.string format])) (defn find-where "Returns the the first item in `coll` with its index for which `(p song)` @@ -35,11 +36,22 @@ (str/lower-case) (keyword))) -(defn format-duration [seconds] - (let [hours (quot seconds 3600) - minutes (quot (rem seconds 3600) 60) - seconds (rem seconds 60)] - (-> (cond-> "" - (> hours 0) (str hours "h ") - (> minutes 0) (str minutes "m ")) - (str seconds "s")))) +(defn- brief-duration [hours minutes seconds] + (str (when (> hours 0) + (format "%02d:" hours)) + (format "%02d:%02d" minutes seconds))) + +(defn- long-duration [hours minutes seconds] + (str/trim + (cond-> "" + (> hours 0) (str hours "h ") + (> minutes 0) (str minutes "m ") + (> 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)))) diff --git a/src/sass/app.sass b/src/sass/app.sass index 0fd3710..56f7608 100644 --- a/src/sass/app.sass +++ b/src/sass/app.sass @@ -64,19 +64,30 @@ overflow: hidden text-overflow: ellipsis - .progress-bar + .progress-indicators // hide progress bar on mobile display: none +tablet - display: block + display: flex flex-grow: 3 - position: relative height: 1rem - .complete-song, - .buffered-part, - .played-back + .progress-info-text + color: whitesmoke + 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 position: absolute top: 0 @@ -90,19 +101,20 @@ position: relative top: 50% - .complete-song + + .complete-song-bar width: 100% &:after background: rgb(93,93,93) - .buffered-part + .buffered-part-bar cursor: pointer &:after background: rgb(143,143,143) - .played-back + .played-back-bar pointer-events: none &:after diff --git a/test/cljs/airsonic_ui/helpers_test.cljs b/test/cljs/airsonic_ui/helpers_test.cljs index 6925b45..42b2212 100644 --- a/test/cljs/airsonic_ui/helpers_test.cljs +++ b/test/cljs/airsonic_ui/helpers_test.cljs @@ -31,3 +31,15 @@ (is (= :hello-world (helpers/kebabify :HelloWorld))) (is (= :how-are-you (helpers/kebabify :howAreYou))) (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)))))