packages feed

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"