haskell-player 0.1.3.1 → 0.1.3.2
raw patch · 3 files changed
+73/−38 lines, 3 files
Files
- haskell-player.cabal +3/−2
- src/Sound/Player.hs +2/−32
- src/Sound/Player/Widgets.hs +68/−4
haskell-player.cabal view
@@ -1,7 +1,8 @@ name: haskell-player-version: 0.1.3.1+version: 0.1.3.2 synopsis: A terminal music player based on afplay-description: Please see README.md+description: A minimal graphical interface on top of afplay and afinfo+ built using brick. homepage: https://github.com/potomak/haskell-player license: BSD3 license-file: LICENSE
src/Sound/Player.hs view
@@ -24,7 +24,6 @@ import Data.List (isPrefixOf, stripPrefix) import Data.Maybe (fromMaybe) import qualified Data.Vector as Vec-import GHC.Float (double2Float) import qualified Graphics.Vty as V import Lens.Micro ((^.)) import System.Directory (doesDirectoryExist, getDirectoryContents)@@ -37,41 +36,13 @@ import Sound.Player.Types (Song(Song, songStatus), PlayerApp(PlayerApp, songsList, playerStatus, playback), Playback(Playback, playhead), Status(Play, Pause, Stop), PlayerEvent(VtyEvent, PlayheadAdvance))-import Sound.Player.Widgets (songWidget)+import Sound.Player.Widgets (songWidget, playbackProgressBar) -- | Draws application UI. drawUI :: PlayerApp -> [Widget] drawUI (PlayerApp l _ _ mPlayback) = [ui] where- playheadWidget Nothing = str " "- playheadWidget (Just pb@(Playback _ _ ph d _)) = str $- "Duration: " ++ show d ++- " - Position: " ++ show (d - ph) ++- " - Progress: " ++ show (playheadProgress pb)- playheadProgressBar Nothing = str " "- playheadProgressBar (Just pb@(Playback playPos _ ph _ _)) =- P.progressBar (Just title) (playheadProgress pb)- where- title = path ++ " (" ++ humanDuration ph ++ ")"- songs = l ^. L.listElementsL- (Song _ path _) = songs Vec.! playPos- secondsDuration :: Double -> Int- secondsDuration d = round d `mod` 60- minutesDuration :: Double -> Int- minutesDuration d = round d `div` 60- humanDuration :: Double -> String- humanDuration d =- show (minutesDuration d) ++ ":" ++ padSeconds (secondsDuration d)- padSeconds :: Int -> String- padSeconds s- | length secs < 2 = "0" ++ secs- | otherwise = secs- where- secs = show s- -- A number between 0 and 1 that is current song's progress- playheadProgress (Playback _ _ ph d _) =- 1 - (double2Float ph / double2Float d) label = str "Item " <+> cur <+> str " of " <+> total cur = case l ^. L.listSelectedL of@@ -80,8 +51,7 @@ total = str $ show $ Vec.length $ l ^. L.listElementsL box = B.borderWithLabel label $ L.renderList l (const songWidget) ui = vBox [ box- , playheadProgressBar mPlayback- , playheadWidget mPlayback+ , playbackProgressBar mPlayback l , str $ "Press enter to play/stop, spacebar to pause/resume, " ++ "left/right to play prev/next song, " ++ "q to exit."
src/Sound/Player/Widgets.hs view
@@ -1,17 +1,81 @@ module Sound.Player.Widgets (- songWidget+ songWidget,+ playbackProgressBar ) where import Brick.Types (Widget)-import Brick.Widgets.Core ((<+>), str, fill, vLimit)+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))+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 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