hum-0.2.0.0: src/Hum/Views/Library.hs
-- | Module : Hum.Views.Library
-- Copyright : (c) Itai Y. Efrat 2020-2021
-- License : GPLv2-or-later (see LICENSE)
-- Maintainer : Itai Y. Efrat <itai3397@gmail.com>
--
-- Functions for the Library view.
module Hum.Views.Library where
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 qualified Data.Vector as V
import qualified Network.MPD as MPD
import Hum.Utils
-- | Draw left column in Library view.
drawLibraryLeft :: HumState -> Widget Name
drawLibraryLeft st = reportExtent LibraryLeft $
Widget Greedy Greedy $ do
ctx <- getContext
let vsize = ctx ^. windowHeightL - 6 -- HACK Don't hardcode nowplaying size?
render $ hCenter
( visible
. vLimit vsize
. center
$ hBorder
<=> hCenter
(renderList (const $ libraryRow st LibraryLeft)
((focLib . focus $ st) == FocArtists)
(MPD.toText <$> st ^. libraryL . artistsL)
)
)
-- | Draw middle column in Library view.
drawLibraryMid :: HumState -> Widget Name
drawLibraryMid st = reportExtent LibraryMid $
Widget Greedy Greedy $ do
ctx <- getContext
let vsize = ctx ^. windowHeightL - 6 -- HACK Don't hardcode nowplaying size?
render $ hCenter
( visible
. vLimit vsize
. center
$ hBorder
<=> hCenter
(renderList (const $ libraryAlbumRow)
((focLib . focus $ st) == FocAlbums)
(st ^. libraryL . yalbumsL)
)
)
-- | Draw right column in Library view.
drawLibraryRight :: HumState -> Widget Name
drawLibraryRight st = reportExtent LibraryRight $
Widget Greedy Greedy $ do
ctx <- getContext
let vsize = ctx ^. windowHeightL - 6 -- HACK Don't hardcode nowplaying size?
render $ hCenter
( visible
. vLimit vsize
. center
$ hBorder
<=> hCenter
(renderList (const $ librarySongRow st)
((focLib . focus $ st) == FocSongs)
(st ^. libraryL . songsL)
)
)
-- | Draw generic column row in Library view.
libraryRow :: HumState -> Name -> T.Text -> Widget n -- TODO refactor?
libraryRow _ name val =
withAttr
(case name of
LibraryLeft -> artistAttr
LibraryMid -> albumAttr
_ -> listAttr
)
$ column Nothing (Pad 1) Max
$ txt val
-- | Draw row in album column in Library view.
libraryAlbumRow :: (MPD.Value,MPD.Value) -> Widget n
libraryAlbumRow (yr,al) =
let year = MPD.toText yr
album = MPD.toText al
yearW = withAttr dateAttr $ column (Just (Col 7)) Max Max $
if T.null year
then txt " "
else txt "(" <+> txt (T.take 4 year) <+> txt ")"
albumW = withAttr albumAttr $ column Nothing Max Max $ txt album
in yearW <+> albumW
-- | Draw row in song column in Library view.
librarySongRow :: HumState -> MPD.Song -> Widget n
librarySongRow st song =
let pathsInQueue =
(MPD.sgFilePath <$>) . (fst <$>) . listElements . queue $ st
title = meta (MPD.toText . MPD.sgFilePath $ song) MPD.Title song
titleW = withAttr titleAttr $ column Nothing Max Max $ txt title
track = meta "-" MPD.Track song
trackW = withAttr trackAttr $ column (Just (Col 3)) Max (Pad 1) $ txt track
in (if MPD.sgFilePath song `elem` pathsInQueue
then withAttr titleBoldAttr
else id
)
$ trackW <+> titleW
-- | Move focus right in Library view.
libraryMoveRight :: FocLib -> FocLib
libraryMoveRight FocArtists = FocAlbums
libraryMoveRight _ = FocSongs
-- | Move focus left in Library view.
libraryMoveLeft :: FocLib -> FocLib
libraryMoveLeft FocSongs = FocAlbums
libraryMoveLeft _ = FocArtists
-- | Draw Library view.
drawViewLibrary :: HumState -> Widget Name
drawViewLibrary st =
drawLibraryLeft st <+> drawLibraryMid st <+> drawLibraryRight st
-- | Move focused library column by given function
libraryMove
:: (forall e . List Name e -> List Name e) -- ^ Function to move the focused column with
-> HumState
-> EventM Name HumState
libraryMove moveFunc s =
let libfoc = s ^. focusL . focLibL
in case libfoc of
FocArtists -> rebuildLibArtists $ s & libraryL . artistsL %~ moveFunc
FocAlbums -> rebuildLibAlbums $ s & libraryL . yalbumsL %~ moveFunc
FocSongs -> do
pure $ s & libraryL . songsL %~ moveFunc
-- | Add selected element in Library view to queue.
-- If the element is an album or artist add all songs under it.
libraryAddtoQ
:: Bool -- ^ Play first item added to queue
-> HumState
-> EventM Name HumState
libraryAddtoQ play s =
let libfoc = s ^. focusL . focLibL
in
case libfoc of
FocArtists -> do
let martist = snd <$> listSelectedElement (s ^. libraryL . artistsL)
songs <-liftIO $ maybe (pure empty) songsOfArtist martist
songBulkAddtoQ play songs s
FocAlbums -> do
let malbum = snd . snd <$> listSelectedElement (s ^. libraryL . yalbumsL)
songs <- liftIO $ maybe (pure empty) songsOfAlbum malbum
songBulkAddtoQ play songs s
FocSongs -> do
let songs = maybe V.empty V.singleton $ snd <$> listSelectedElement
(s ^. libraryL . songsL)
songBulkAddtoQ play songs s
-- | Search focused library column for next instance of last search.
librarySearch
:: Bool -- ^ Search direction, True for forward.
-> HumState
-> EventM Name HumState
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
rebuildLibArtists
$ s
& libraryL
. artistsL
%~ (dir . listFindBy (stringySearch searchkey) . dir)
FocAlbums -> do
rebuildLibAlbums
$ s
& libraryL
. yalbumsL
%~ (dir . listFindBy (stringySearch searchkey . snd) . dir)
FocSongs -> do
pure
$ s
& libraryL
. songsL
%~ (dir . listFindBy (songSearch searchkey [MPD.Title]) . dir)
-- | handle key inputs for Library view.
handleEventLibrary
:: HumState -> BrickEvent Name HumEvent -> EventM Name (Next HumState)
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 (listMoveTo (-1)) s
EvKey (KChar 'g') [] -> continue =<< libraryMove (listMoveTo 0) s -- TODO change this to 'gg', somehow
EvKey (KChar '`') [] -> continue =<< rebuildLibArtists (s & libraryL . yalbumSortL %~ not)
_ -> continue s
_ -> continue s