module Sound.Player.Widgets ( songWidget, playbackProgressBar ) where import Brick.Types (Widget) import Brick.Widgets.Core ((<+>), str, fill, vLimit, vBox) import qualified Brick.Widgets.List as L import qualified Brick.Widgets.ProgressBar as P import qualified Data.Vector as Vec import GHC.Float (double2Float) import Lens.Micro ((^.)) import Sound.Player.Types (Song(Song), Status(Play, Pause), Playback(Playback)) -- | A song 'Widget', one of the items in the songs list. songWidget :: Song -> Widget songWidget (Song _ path status) = vLimit 1 $ str (statusSymbol status) <+> str " " <+> str path <+> fill ' ' where statusSymbol Play = "♫" statusSymbol Pause = "•" statusSymbol _ = " " -- | A 'Widget' that shows two progress bars, the top bar shows the path of -- the playing song, the bottom bar shows the playhead position, song duration -- and playback percentage. playbackProgressBar :: Maybe Playback -> L.List Song -> Widget playbackProgressBar mPlayback l = vBox [ titlePlaybackProgressBar mPlayback l , infoPlaybackProgressBar mPlayback ] -- | A 'Widget' that shows a progress bar with the path of the song. titlePlaybackProgressBar :: Maybe Playback -> L.List Song -> Widget titlePlaybackProgressBar Nothing _ = str " " titlePlaybackProgressBar (Just pb@(Playback playPos _ _ _ _)) l = P.progressBar (Just path) (playbackProgress pb) where songs = l ^. L.listElementsL (Song _ path _) = songs Vec.! playPos -- | A 'Widget' that shows a progress bar with the playhead position, song -- duration and playback percentage. infoPlaybackProgressBar :: Maybe Playback -> Widget infoPlaybackProgressBar Nothing = str " " infoPlaybackProgressBar (Just pb@(Playback _ _ ph d _)) = P.progressBar (Just title) progress where progress = playbackProgress pb percentage :: Integer percentage = round (progress * 100) title = formatSeconds (d - ph) ++ " / " ++ formatSeconds d ++ " ~ " ++ show percentage ++ "%" -- | A 'Float' number between 0 and 1 that is playing song's progress. playbackProgress :: Playback -> Float playbackProgress (Playback _ _ ph d _) = 1 - (double2Float ph / double2Float d) -- | Returns a string that is a time formatted as /mm:ss/ formatSeconds :: Double -> String formatSeconds s = pad (minutes s) ++ ":" ++ pad (seconds s) where seconds :: Double -> Int seconds n = round n `mod` 60 minutes :: Double -> Int minutes n = round n `div` 60 pad :: Int -> String pad n | length ns < 2 = "0" ++ ns | otherwise = ns where ns = show n