hum-0.1.0.0: src/Hum/Views/Library.hs
{-#LANGUAGE RankNTypes#-}
-- |
module Hum.Views.Library where
import Prelude hiding ( Down )
import Hum.Types
import Brick.Types
import Graphics.Vty.Input.Events
import Brick.Main
import Brick.Widgets.Core
import Brick.Widgets.Center
import Brick.Widgets.Border
import Control.Lens
import Brick.Widgets.List
import Hum.Attributes
import Hum.Views.Common
import Hum.Rebuild
import qualified Data.Text as T
import Network.MPD ( withMPD )
import qualified Network.MPD as MPD
import qualified Data.Map.Strict as Map
import Hum.Utils
drawLibraryLeft :: HState -> Widget Name
drawLibraryLeft st =
let vsize = case join $ Map.lookup LibraryLeft $ extentMap st of
Just e -> snd . extentSize $ e
Nothing -> 20
in reportExtent LibraryLeft $ hCenter
( viewport LibraryLeft Vertical
. visible
. vLimit vsize
. center
$ hBorder
<=> hCenter
(renderList (const $ libraryRow st LibraryLeft)
((focLib . focus $ st) == FocArtists)
(MPD.toText <$> st ^. libraryL . artistsL)
)
)
drawLibraryMid :: HState -> Widget Name
drawLibraryMid st =
let vsize = case join $ Map.lookup LibraryMid $ extentMap st of
Just e -> snd . extentSize $ e
Nothing -> 20
in reportExtent LibraryMid $ hCenter
( viewport LibraryMid Vertical
. visible
. vLimit vsize
. center
$ hBorder
<=> hCenter
(renderList (const $ libraryRow st LibraryMid)
((focLib . focus $ st) == FocAlbums)
(MPD.toText <$> st ^. libraryL . albumsL)
)
)
drawLibraryRight :: HState -> Widget Name
drawLibraryRight st =
let vsize = case join $ Map.lookup LibraryRight $ extentMap st of
Just e -> snd . extentSize $ e
Nothing -> 20
in reportExtent LibraryRight $ hCenter
( viewport LibraryRight Vertical
. visible
. vLimit vsize
. center
$ hBorder
<=> hCenter
(renderList (const $ librarySongRow st)
((focLib . focus $ st) == FocSongs)
(st ^. libraryL . songsL)
)
)
libraryRow :: HState -> Name -> T.Text -> Widget n
libraryRow _ name val =
withAttr
(case name of
LibraryLeft -> queueArtistAttr
LibraryMid -> queueAlbumAttr
_ -> listAttr
)
$ column Nothing (Pad 1) Max
$ txt val
librarySongRow :: HState -> MPD.Song -> Widget n
librarySongRow st song =
let pathsInQueue =
(MPD.sgFilePath <$>) . (fst <$>) . listElements . queue $ st
in withAttr
(if MPD.sgFilePath song `elem` pathsInQueue
then queueTitleBoldAttr
else queueTitleAttr
)
$ column Nothing (Pad 1) Max
$ txt (meta (MPD.toText . MPD.sgFilePath $ song) MPD.Title song)
libraryMoveRight :: FocLib -> FocLib
libraryMoveRight FocArtists = FocAlbums
libraryMoveRight _ = FocSongs
libraryMoveLeft :: FocLib -> FocLib
libraryMoveLeft FocSongs = FocAlbums
libraryMoveLeft _ = FocArtists
drawViewLibrary :: HState -> Widget Name
drawViewLibrary st =
drawLibraryLeft st <+> drawLibraryMid st <+> drawLibraryRight st
libraryMove
:: (forall e . List Name e -> List Name e) -> HState -> EventM Name HState
libraryMove moveFunc s =
let libfoc = s ^. focusL . focLibL
in case libfoc of
FocArtists -> rebuildLibArtists $ s & libraryL . artistsL %~ moveFunc
FocAlbums -> rebuildLibAlbums $ s & libraryL . albumsL %~ moveFunc
FocSongs -> do
pure $ s & libraryL . songsL %~ moveFunc
libraryAddtoQ :: Bool -> HState -> EventM Name HState
libraryAddtoQ play s =
let libfoc = s ^. focusL . focLibL
in
case libfoc of
FocArtists -> do
songs <-
liftIO
(songsOfArtist
(snd <$> listSelectedElement (s ^. libraryL . artistsL))
)
songBulkAddtoQ play songs s
FocAlbums -> do
songs <-
liftIO
(songsOfAlbum
(snd <$> listSelectedElement (s ^. libraryL . albumsL))
)
songBulkAddtoQ play songs s
FocSongs -> do
let maybeFilePath = MPD.sgFilePath . snd <$> listSelectedElement
(s ^. libraryL . songsL)
traverse_
(\sel -> liftIO
(withMPD $ MPD.addId sel Nothing >>= if play
then MPD.playId
else const pass
)
)
maybeFilePath
song <- liftIO (withMPD MPD.currentSong)
pure s { currentSong = fromRight Nothing song, queue = queue s }
librarySearch :: Bool -> HState -> EventM Name HState
librarySearch direction s =
let libfoc = s ^. focusL . focLibL
dir = if direction then id else listReverse
searchkey = fromMaybe "" ((s ^. exL . searchHistoryL) !!? 0)
in if searchkey == ""
then pure s
else case libfoc of
FocArtists -> do
extentMap <- updateExtentMap
rebuildLibArtists
$ (s { extentMap })
& libraryL
. artistsL
%~ (dir . listFindBy (stringySearch searchkey) . dir)
FocAlbums -> do
extentMap <- updateExtentMap
rebuildLibAlbums
$ (s { extentMap })
& libraryL
. albumsL
%~ (dir . listFindBy (stringySearch searchkey) . dir)
FocSongs -> do
extentMap <- updateExtentMap
pure
$ s { extentMap }
& libraryL
. songsL
%~ (dir . listFindBy (songSearch searchkey [MPD.Title]) . dir)
handleEventLibrary
:: HState -> BrickEvent Name HumEvent -> EventM Name (Next HState)
handleEventLibrary s e = case e of
VtyEvent vtye -> case vtye of
EvKey (KChar 'j') [] -> continue =<< libraryMove listMoveDown s
EvKey (KChar 'k') [] -> continue =<< libraryMove listMoveUp s
EvKey (KChar 'l') [] -> continue $ s & focusL . focLibL %~ libraryMoveRight
EvKey (KChar 'h') [] -> continue $ s & focusL . focLibL %~ libraryMoveLeft
EvKey (KChar 'n') [] ->
continue =<< librarySearch (s ^. exL . searchDirectionL) s
EvKey (KChar 'N') [] ->
continue =<< librarySearch (s ^. exL . searchDirectionL & not) s
EvKey KEnter [] ->
continue =<< libraryMove listMoveDown =<< libraryAddtoQ True s
EvKey (KChar ' ') [] ->
continue =<< libraryMove listMoveDown =<< libraryAddtoQ False s
EvKey (KChar 'G') [] ->
continue =<< libraryMove (\ls -> listMoveBy (length ls) ls) s
EvKey (KChar 'g') [] -> continue =<< libraryMove (listMoveTo 0) s -- TODO change this to 'gg', somehow
_ -> continue s
_ -> continue s
addToPl :: EventM Name HState
addToPl = error "not implemented"