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

Implement progress bar with html elements, fixes #39

This commit is contained in:
Arne Schlüter 2019-01-22 22:20:43 +01:00
commit a9fbe5c741
2 changed files with 81 additions and 79 deletions

View file

@ -1,81 +1,34 @@
(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.components.highres-canvas.views :refer [canvas]]
[airsonic-ui.helpers :refer [add-classes muted-dispatch]] [airsonic-ui.helpers :refer [add-classes muted-dispatch]]
[airsonic-ui.views.cover :refer [cover]] [airsonic-ui.views.cover :refer [cover]]
[airsonic-ui.views.icon :refer [icon]])) [airsonic-ui.views.icon :refer [icon]]))
;; currently playing / coming next / audio controls... ;; currently playing / coming next / audio controls...
;; FIXME: Sometimes items don't have a duration
(def progress-bar-color "rgb(93,93,93)")
(def progress-bar-color-buffered "rgb(143,143,143)")
(def progress-bar-color-active "whitesmoke")
(defn draw-progress [ctx current-time buffered duration]
(let [width (.. ctx -canvas -clientWidth)
height (.. ctx -canvas -clientHeight)
padding 5
buffered-x (+ padding (* (- width (* 2 padding)) (min 1 (/ buffered duration))))
current-x (+ padding (* (- width (* 2 padding)) (min 1 (/ current-time duration))))]
;; vertically center everything
(.translate ctx 0.5 (+ (Math/ceil (/ height 2)) 0.5))
;; draw complete bar
(set! (.-strokeStyle ctx) progress-bar-color)
(doto ctx
(.beginPath)
(.moveTo padding 0)
(.lineTo (- width (* 2 padding)) 0)
(.stroke))
;; draw the buffered part
(set! (.-strokeStyle ctx) progress-bar-color-buffered)
(doto ctx
(.beginPath)
(.moveTo padding 0)
(.lineTo buffered-x 0)
(.stroke))
;; draw the part that's already played
(set! (.-strokeStyle ctx) progress-bar-color-active)
(doto ctx
(.beginPath)
(.moveTo padding 0)
(.lineTo current-x 0)
(.stroke))
;; draw a dot marking the current time
(set! (.-fillStyle ctx) progress-bar-color-active)
(doto ctx
(.beginPath)
(.arc current-x 0 (/ padding 2) 0 (* Math/PI 2))
(.fill))))
(defn current-progress [current-time buffered duration]
[canvas {:class "current-progress-canvas"
:draw #(draw-progress % current-time buffered duration)}])
;; FIXME: It's ugly to have the canvas padding and styling scattered everywhere (sass, drawing code above, and here)
(defn seek (defn seek
"Calculates the position of the click and sets current playback accordingly" "Calculates the position of the click and sets current playback accordingly"
[ev] [ev]
(let [x (- (.. ev -nativeEvent -pageX) (let [x-ratio (/ (.. ev -nativeEvent -layerX)
(.. ev -target getBoundingClientRect -left)) (.. ev -target -parentElement getBoundingClientRect -width))]
width (- (.. ev -target -nextElementSibling -clientWidth) 10)] ;; <- 10 = 2 * canvas-padding (dispatch [:audio-player/seek x-ratio])))
(dispatch [:audio-player/seek (/ x width)])))
(defn buffered-part (defn- ratio->width [ratio]
[buffered duration] (str (.toFixed (* 100 ratio) 2) "%"))
(let [width (min 100 (* (/ buffered duration) 100))]
[:div.buffered-part {:on-click seek
:style {:width (str "calc(" width "% - 1rem - 10px)")}}]))
(defn progress-bar [song status] (defn progress-bar [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)
[:article.progress-bar buffered-width (ratio->width (/ buffered duration))
[buffered-part buffered duration] played-width (ratio->width (/ current-time duration))]
[current-progress current-time buffered 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]]]))
(defn playback-info [song status] (defn playback-info [song status]
[:a.playback-info.media [:a.playback-info.media
@ -143,8 +96,8 @@
;; 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]
[playback-controls is-playing?]
[progress-bar current-song playback-status] [progress-bar current-song playback-status]
[playback-controls is-playing?]
[playback-mode-controls playlist]] [playback-mode-controls playlist]]
;; not playing anything ;; not playing anything
[:p.navbar-item.idle-notification "No audio playing"])]])) [:p.navbar-item.idle-notification "No audio playing"])]]))

View file

@ -18,11 +18,14 @@
+loader +loader
// bottom bar // bottom bar
.has-navbar-bottom
padding-bottom: 64px
.audio-player .audio-player
// first clear some of that navigation styling // first clear some of that navigation styling
background-color: $dark background-color: $dark
color: $light color: $light
min-height: 0 min-height: 64px
.navbar-menu .navbar-menu
padding: 0 padding: 0
@ -37,6 +40,7 @@
// ... or with all the bells and whistles // ... or with all the bells and whistles
.audio-interaction .audio-interaction
display: flex display: flex
flex-grow: 1
align-items: center align-items: center
.playback-info .playback-info
@ -45,39 +49,84 @@
flex-grow: 1 flex-grow: 1
color: inherit color: inherit
.artist-and-title > * .media-left
display: inline-block margin-right: .6rem
.artist-and-title
margin-right: .6rem
.artist,
.song-title
display: block
white-space: nowrap white-space: nowrap
width: 100% width: 100%
max-width: 100%
overflow: hidden
text-overflow: ellipsis text-overflow: ellipsis
.progress-bar .progress-bar
// hide progress bar on mobile // hide progress bar on mobile
display: none display: none
@include =tablet +tablet
display: block display: block
flex-grow: 1 flex-grow: 3
position: relative position: relative
height: 1rem
.complete-song,
.buffered-part,
.played-back
height: 1rem
position: absolute
top: 0
left: 0
// these are the actual bars
&:after
content: ''
display: block
height: 1px
position: relative
top: 50%
.complete-song
width: 100%
&:after
background: rgb(93,93,93)
.buffered-part .buffered-part
position: absolute
top: .5rem
left: calc(.5rem + 5px)
height: 1rem
cursor: pointer cursor: pointer
.current-progress-canvas &:after
display: block background: rgb(143,143,143)
height: 1rem
width: 100% .played-back
pointer-events: none
&:after
background: whitesmoke
.played-back-knob
position: absolute
width: 5px
height: 5px
left: 100%
top: 50%
margin-left: -2.5px
margin-top: -2.5px
background: whitesmoke
border-radius: 100%
// buttons to control current playback and playlist behavior // buttons to control current playback and playlist behavior
.playback-controls, .playback-controls,
.playback-mode-controls .playback-mode-controls
flex-shrink: 0 flex-shrink: 0
padding: .3rem padding-right: .6rem
.playback-controls
padding-left: .6rem
// preview card for album or artist listings // preview card for album or artist listings
.preview-card .preview-card