mywork-1.0.1.0: lib/Panes/LocationInput.hs
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
module Panes.LocationInput
(
LocationInputPane
, initLocInput
, isLocInputActive
, locationInputResults
)
where
import Brick hiding ( Location )
import Brick.Focus
import Brick.Forms
import Brick.Panes
import qualified Brick.Widgets.Center as C
import Control.Lens
import Data.Maybe ( isJust )
import qualified Data.Sequence as Seq
import Data.Text ( Text )
import qualified Data.Text as T
import Data.Time.Calendar ( Day )
import qualified Graphics.Vty as Vty
import Defs
import Panes.Common.Attrs
import Panes.Common.Inputs
data LocationInputPane
data NewLoc = NewLoc { _nlName :: LocationSpec
, _nlDay :: Maybe Day
}
makeLenses ''NewLoc
blankNewLoc :: NewLoc
blankNewLoc = NewLoc (RemoteSpec "") Nothing
type LocForm = Form NewLoc MyWorkEvent WName
instance Pane WName MyWorkEvent LocationInputPane where
data (PaneState LocationInputPane MyWorkEvent) = NL { nLF :: Maybe LocForm
-- Just == pane active
, nLoc :: Maybe Location
-- reset to Nothing when
-- nLF transitions Nothing
-- to Just
, nProj :: ProjectName
, nOrig :: Maybe Location
, nErr :: Maybe Text
}
type (EventType LocationInputPane WName MyWorkEvent) = BrickEvent WName MyWorkEvent
initPaneState _ = NL Nothing Nothing (ProjectName "") Nothing Nothing
drawPane ps _gs =
C.centerLayer
. modalB ((maybe "New" (const "Edit") $ nOrig ps)
<> " " <> (let ProjectName pnm = nProj ps in T.pack $ show pnm)
<> " Location")
. vLimit 25
. hLimitPercent 65
. (\f -> vBox [ renderForm f
, padBottom (Pad 1) $ withAttr a'Error
$ maybe (txt " ") txt (nErr ps)
, emptyWidget
, vLimit 1 (fill ' ' <+> str "Ctrl-D = accept"
<+> fill ' ' <+> str "ESC = abort"
<+> fill ' ')
]) <$> nLF ps
focusable _ ps = case nLF ps of
Nothing -> mempty
Just f -> Seq.fromList $ focusRingToList $ formFocus f
handlePaneEvent _ = \case
VtyEvent (Vty.EvKey Vty.KEsc []) -> nLFL %%~ const (return Nothing)
VtyEvent (Vty.EvKey (Vty.KChar 'd') [Vty.MCtrl]) -> \s ->
let pf = s ^. nLFL
np form = Location { location = form ^. nlName
, locatedOn = form ^. nlDay
, notes = mempty
, locCore = LocRT
{ locValid = True -- assumed
}
}
in if maybe False allFieldsValid pf
then do let l = np . formState <$> pf
return $ s & nLFL .~ Nothing & newLocation .~ l
else
let badflds = maybe "none"
(foldr (\n a -> if T.null a
then T.pack n
else T.pack n <> ", " <> a) ""
. fmap show . invalidFields)
pf
errmsg = "Correct invalid entries before accepting: "
in return $ s { nErr = Just $ errmsg <> badflds }
ev -> \s -> validateForm
$ s { nErr = Nothing }
& (nLFL . _Just %%~ \w -> nestEventM' w (handleFormEvent ev))
nLFL :: Lens' (PaneState LocationInputPane MyWorkEvent) (Maybe LocForm)
nLFL f s = (\n -> s { nLF = n }) <$> f (nLF s)
isLocInputActive :: PaneState LocationInputPane MyWorkEvent -> Bool
isLocInputActive = isJust . nLF
newLocation :: Lens' (PaneState LocationInputPane MyWorkEvent) (Maybe Location)
newLocation f s = (\n -> s { nLoc = n }) <$> f (nLoc s)
-- | Returns the original location name (if any) and the new Location
-- specification.
locationInputResults :: PaneState LocationInputPane MyWorkEvent
-> (Maybe LocationSpec, Maybe Location)
locationInputResults ps = (view locationL <$> nOrig ps, nLoc ps)
validateForm :: EventM WName es (PaneState LocationInputPane MyWorkEvent)
-> EventM WName es (PaneState LocationInputPane MyWorkEvent)
validateForm inner = do
s <- inner
case s ^. nLFL of
Nothing -> return s
Just pf ->
do (tgt,valid) <- validateLocationInput False $ formState pf ^. nlName
return $ s & nLFL %~ fmap (setFieldValid valid tgt)
initLocInput :: ProjectName
-> [Location]
-> Maybe Location
-> PaneState LocationInputPane MyWorkEvent
-> PaneState LocationInputPane MyWorkEvent
initLocInput prjName locs mbLoc ps =
case nLF ps of
Just _ -> ps
Nothing ->
let label s = padBottom (Pad 1) . label' s
label' s w = (vLimit 1 $ hLimit labelWidth
$ fill ' ' <+> str s <+> str ": ") <+> w
labelWidth = 15
nlForm =
newForm
[
label "Location" @@= locationInput locs mbLoc False nlName
, label "Date" @@= mbDateInput nlDay
]
(case mbLoc of
Nothing -> blankNewLoc
Just l -> NewLoc { _nlName = l ^. locationL
, _nlDay = l ^. locatedOnL
}
)
in NL { nLF = Just nlForm
, nProj = prjName
, nLoc = Nothing
, nOrig = mbLoc
, nErr = Nothing
}