mp-0.1.3: src/Mp/UI/BrowserPage.hs
{-
* Programmer: Piotr Borek
* E-mail: piotrborek@op.pl
* Copyright 2014 Piotr Borek
*
* Distributed under the terms of the GPL (GNU Public License)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
module Mp.UI.BrowserPage (
BrowserPage (..),
BrowserPageWidget,
makeUIBrowserPage
) where
import Graphics.Vty.Widgets.All
import Graphics.Vty hiding (Button)
import qualified Data.HashMap.Strict as Map
import qualified Data.Text as T
import Data.ConfigFile
import Data.List
import Data.Maybe
import Data.Functor
import System.Directory
import System.FilePath.Posix
import Control.Monad
import Control.Concurrent
import Mp.Utils.Colors
import Mp.Utils.Exception
import Mp.Utils.Utils
import Mp.Configuration.Configuration
import Mp.UI.QueuePage
type BrowserPageWidget = Widget (List String FormattedText)
data BrowserPage = BrowserPage {
browserPageWidget :: BrowserPageWidget,
browserPageFocusGroup :: Widget FocusGroup,
browserPageReset :: IO ()
}
data BrowserState = BrowserState {
topDir :: !String,
dirCache :: Map.HashMap String String
}
makeUIBrowserPage :: ConfigParser -> QueuePage -> IO BrowserPage
makeUIBrowserPage conf queuePage = do
fg <- newFocusGroup
lst <- newList (browserActiveAttribute conf ) 1
>>= withBrowserBgAttribute conf
let musicDir = getMusicDirectory conf
setCurrentDirectory musicDir
browserState <- newMVar BrowserState {
topDir = musicDir,
dirCache = Map.empty
}
addAllFilesToList lst musicDir
_ <- addToFocusGroup fg lst
_ <- addToFocusGroup fg lst
let keyHandler = \_ k _ ->
case k of
KEnter -> do
maybeSel <- getSelected lst
let (_, (value, _)) = fromJust maybeSel
modifyMVar_ browserState $ changeDirectory lst value
return True
KASCII '!' -> do
modifyMVar_ browserState $ changeDirectory lst musicDir
return True
KASCII '@' -> do
modifyMVar_ browserState $ changeDirectory lst ".."
return True
KASCII ' ' -> do
selectCurrentFile lst
return True
KASCII 'd' -> do
removeCurrentFile lst
return True
_ -> return False
lst `onKeyPressed` keyHandler
return BrowserPage {
browserPageWidget = lst,
browserPageFocusGroup = fg,
browserPageReset = resetBrowser lst browserState
}
where
addFileToList list text = addToList list text =<< (plainText (T.pack text) >>= withBrowserFileAttribute conf)
addDirToList list text = addToList list text =<< (plainText (T.pack text) >>= withBrowserDirectoryAttribute conf)
addAllFilesToList list dir = do
clearList list
files <- sort <$> getDirectoryContents dir
forM_ files $ \file -> do
exists <- doesDirectoryExist $ dir </> file
when (and [exists, file /= "."]) $ addDirToList list file
forM_ files $ \file -> do
exists <- doesFileExist $ dir </> file
when exists $ addFileToList list file
changeDirectory list dir st = do
let oldDir = topDir st
ok <- try' $ setCurrentDirectory $ oldDir </> dir
if (isJust ok)
then do
newDir <- getCurrentDirectory
let newSt = if dir == ".."
then
st {
topDir = newDir
}
else
st {
topDir = newDir,
dirCache = Map.insert oldDir dir $ dirCache st
}
addAllFilesToList list newDir
when (dir == "..") $ do
let maybeVal = Map.lookup newDir $ dirCache newSt
when (isJust maybeVal) $ do
maybeIndex <- listFindFirst list $ fromJust maybeVal
case maybeIndex of
Just index -> setSelected list index
Nothing -> return ()
return newSt
else
return st
selectCurrentFile list = do
maybeSel <- getSelected list
when (isJust maybeSel) $ do
let (index, (file, item)) = fromJust maybeSel
currDir <- getCurrentDirectory
when (currDir /= "..") $ do
_ <- withBrowserSelectedAttribute conf item
setSelected list $ succ index
addAllFiles currDir file
return ()
addAllFiles dir file
| file == "." = return ()
| file == ".." = return ()
| otherwise = do
exists <- doesDirectoryExist $ dir </> file
if exists
then do
let newDir = dir </> file
files <- try' (sort <$> getDirectoryContents newDir)
when (isJust files) $ do
forM_ (fromJust files) $ \f -> do
addAllFiles newDir f
else
queuePageAdd queuePage dir file
removeCurrentFile list = do
maybeSel <- getSelected list
when (isJust maybeSel) $ do
let (index, (file, item)) = fromJust maybeSel
currDir <- getCurrentDirectory
when (currDir /= "..") $ do
whenM (doesDirectoryExist $ currDir </> file) $ do
_ <- withBrowserDirectoryAttribute conf item
return ()
whenM (doesFileExist $ currDir </> file) $ do
_ <- withBrowserFileAttribute conf item
return ()
setSelected list $ succ index
removeAllFiles currDir file
return ()
removeAllFiles dir file
| file == "." = return ()
| file == ".." = return ()
| otherwise = do
exists <- doesDirectoryExist $ dir </> file
if exists
then do
let newDir = dir </> file
files <- try' (sort <$> getDirectoryContents newDir)
when (isJust files) $ do
forM_ (fromJust files) $ \f -> do
removeAllFiles newDir f
else
queuePageRemove queuePage dir file
resetBrowser widget browserState = do
st <- readMVar browserState
maybeSel <- getSelected widget
addAllFilesToList widget $ topDir st
when (isJust maybeSel) $ do
let (sel, _) = fromJust maybeSel
setSelected widget sel