{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE RankNTypes #-} module AddCLI where import Lens.Micro import Lens.Micro.TH import qualified Graphics.Vty as V import qualified Brick.Main as M import qualified Brick.Types as T import Brick.Widgets.Core ( (<+>) , (<=>) , hLimit , vLimit , str ) import qualified Brick.Widgets.Center as C import qualified Brick.Widgets.Edit as E import qualified Brick.AttrMap as A import qualified Brick.Focus as F import Brick.Util (on) import ReadConfig (Translator) import qualified Lang.Strings as Str data Name = RecipeName | Description | ServingSize | IngrAmount | IngrUnit | IngrName | IngrAttr | Directions | Tags deriving (Ord, Show, Eq) data FocusChange = FocusDown | FocusUp | FocusLeft | FocusRight deriving Eq data St = St { _focusRing :: F.FocusRing Name , _edit1 :: E.Editor String Name , _edit2 :: E.Editor String Name , _edit3 :: E.Editor String Name , _edit4 :: E.Editor String Name , _edit5 :: E.Editor String Name , _edit6 :: E.Editor String Name , _edit7 :: E.Editor String Name , _edit8 :: E.Editor String Name , _edit9 :: E.Editor String Name } makeLenses ''St drawUI :: Translator -> St -> [T.Widget Name] drawUI t st = [ui] where e1 = F.withFocusRing (st^.focusRing) (E.renderEditor (str . unlines)) (st^.edit1) e2 = F.withFocusRing (st^.focusRing) (E.renderEditor (str . unlines)) (st^.edit2) e3 = F.withFocusRing (st^.focusRing) (E.renderEditor (str . unlines)) (st^.edit3) e4 = F.withFocusRing (st^.focusRing) (E.renderEditor (str . unlines)) (st^.edit4) e5 = F.withFocusRing (st^.focusRing) (E.renderEditor (str . unlines)) (st^.edit5) e6 = F.withFocusRing (st^.focusRing) (E.renderEditor (str . unlines)) (st^.edit6) e7 = F.withFocusRing (st^.focusRing) (E.renderEditor (str . unlines)) (st^.edit7) e8 = F.withFocusRing (st^.focusRing) (E.renderEditor (str . unlines)) (st^.edit8) e9 = F.withFocusRing (st^.focusRing) (E.renderEditor (str . unlines)) (st^.edit9) ui = C.center $ str (t Str.tuiTitle) <=> str " " <=> (str (t Str.tuiName) <+> hLimit 62 e1) <=> str " " <=> (str (t Str.tuiDesc) <+> hLimit 62 (vLimit 4 e2)) <=> str " " <=> (str (t Str.tuiServingSize) <+> hLimit 3 e3) <=> str " " <=> str (t Str.tuiHeaders) <=> (str (t Str.tuiIngrs) <+> hLimit 7 (vLimit 7 e4) <+> hLimit 9 (vLimit 7 e5) <+> hLimit 28 (vLimit 7 e6) <+> hLimit 18 (vLimit 7 e7)) <=> str " " <=> (str (t Str.tuiDirs) <+> hLimit 62 (vLimit 8 e8)) <=> str " " <=> (str (t Str.tuiTags) <+> hLimit 62 (vLimit 1 e9)) <=> str " " <=> str (t Str.tuiHelp1) <=> str (t Str.tuiHelp2) <=> str (t Str.tuiHelp3) <=> str (t Str.tuiHelp4) appEvent :: St -> T.BrickEvent Name e -> T.EventM Name (T.Next St) appEvent st (T.VtyEvent ev) = case ev of V.EvKey V.KEsc [] -> M.halt st V.EvKey (V.KChar '\t') [] -> M.continue $ st & focusRing %~ F.focusNext V.EvKey V.KBackTab [] -> M.continue $ st & focusRing %~ F.focusPrev -- Ctrl + V.EvKey V.KDown [V.MCtrl] -> M.continue $ st & focusRing %~ determineNextFocus FocusDown st V.EvKey V.KUp [V.MCtrl] -> M.continue $ st & focusRing %~ determineNextFocus FocusUp st V.EvKey V.KRight [V.MCtrl] -> M.continue $ st & focusRing %~ determineNextFocus FocusRight st V.EvKey V.KLeft [V.MCtrl] -> M.continue $ st & focusRing %~ determineNextFocus FocusLeft st -- Meta + V.EvKey (V.KChar 'h') [V.MMeta] -> M.continue $ st & focusRing %~ determineNextFocus FocusLeft st V.EvKey (V.KChar 'j') [V.MMeta] -> M.continue $ st & focusRing %~ determineNextFocus FocusDown st V.EvKey (V.KChar 'k') [V.MMeta] -> M.continue $ st & focusRing %~ determineNextFocus FocusUp st V.EvKey (V.KChar 'l') [V.MMeta] -> M.continue $ st & focusRing %~ determineNextFocus FocusRight st _ -> M.continue =<< case F.focusGetCurrent (st^.focusRing) of Just RecipeName -> T.handleEventLensed st edit1 E.handleEditorEvent ev Just Description -> T.handleEventLensed st edit2 E.handleEditorEvent ev Just ServingSize -> T.handleEventLensed st edit3 E.handleEditorEvent ev Just IngrAmount -> T.handleEventLensed st edit4 E.handleEditorEvent ev Just IngrUnit -> T.handleEventLensed st edit5 E.handleEditorEvent ev Just IngrName -> T.handleEventLensed st edit6 E.handleEditorEvent ev Just IngrAttr -> T.handleEventLensed st edit7 E.handleEditorEvent ev Just Directions -> T.handleEventLensed st edit8 E.handleEditorEvent ev Just Tags -> T.handleEventLensed st edit9 E.handleEditorEvent ev Nothing -> return st appEvent st _ = M.continue st determineNextFocus :: FocusChange -> St -> F.FocusRing n -> F.FocusRing n determineNextFocus action st = case action of FocusDown -> case currentFocus of Just RecipeName -> F.focusNext Just Description -> F.focusNext Just ServingSize -> F.focusNext Just IngrAmount -> F.focusNext . F.focusNext . F.focusNext . F.focusNext Just IngrUnit -> F.focusNext . F.focusNext . F.focusNext Just IngrName -> F.focusNext . F.focusNext Just IngrAttr -> F.focusNext Just Directions -> F.focusNext Just Tags -> F.focusNext Nothing -> F.focusNext FocusUp -> case currentFocus of Just RecipeName -> F.focusPrev Just Description -> F.focusPrev Just ServingSize -> F.focusPrev Just IngrAttr -> F.focusPrev . F.focusPrev . F.focusPrev . F.focusPrev Just IngrName -> F.focusPrev . F.focusPrev . F.focusPrev Just IngrUnit -> F.focusPrev . F.focusPrev Just IngrAmount -> F.focusPrev Just Directions -> F.focusPrev . F.focusPrev . F.focusPrev . F.focusPrev Just Tags -> F.focusPrev Nothing -> F.focusPrev FocusLeft -> case currentFocus of Just RecipeName -> F.focusNext . F.focusNext Just Description -> F.focusNext Just ServingSize -> F.focusNext Just IngrAmount -> F.focusNext . F.focusNext . F.focusNext Just IngrUnit -> F.focusPrev Just IngrName -> F.focusPrev Just IngrAttr -> F.focusPrev Just Directions -> F.focusPrev . F.focusPrev . F.focusPrev . F.focusPrev Just Tags -> F.focusPrev . F.focusPrev . F.focusPrev . F.focusPrev . F.focusPrev Nothing -> F.focusNext FocusRight -> case currentFocus of Just RecipeName -> F.focusNext . F.focusNext Just Description -> F.focusNext Just ServingSize -> F.focusNext Just IngrAmount -> F.focusNext Just IngrUnit -> F.focusNext Just IngrName -> F.focusNext Just IngrAttr -> F.focusPrev . F.focusPrev . F.focusPrev Just Directions -> F.focusPrev . F.focusPrev . F.focusPrev . F.focusPrev Just Tags -> F.focusPrev . F.focusPrev . F.focusPrev . F.focusPrev . F.focusPrev Nothing -> F.focusNext where currentFocus = F.focusGetCurrent $ st^.focusRing initialState :: String -> String -> String -> String -> String -> String -> String -> String -> String -> St initialState name desc serving amounts units ingrs attrs dirs tags = St (F.focusRing [RecipeName, Description, ServingSize, IngrAmount, IngrUnit, IngrName, IngrAttr, Directions, Tags]) (E.editor RecipeName (Just 1) name) (E.editor Description Nothing desc) (E.editor ServingSize (Just 1) serving) (E.editor IngrAmount Nothing amounts) (E.editor IngrUnit Nothing units) (E.editor IngrName Nothing ingrs) (E.editor IngrAttr Nothing attrs) (E.editor Directions Nothing dirs) (E.editor Tags (Just 1) tags) theMap :: A.AttrMap theMap = A.attrMap V.defAttr [ (E.editAttr, V.white `on` V.black) , (E.editFocusedAttr, V.black `on` V.white) ] appCursor :: St -> [T.CursorLocation Name] -> Maybe (T.CursorLocation Name) appCursor = F.focusRingCursor (^.focusRing) theApp :: Translator -> M.App St e Name theApp t = M.App { M.appDraw = drawUI t , M.appChooseCursor = appCursor , M.appHandleEvent = appEvent , M.appStartEvent = return , M.appAttrMap = const theMap } getEdit :: Translator -> String -> String -> String -> String -> String -> String -> String -> String -> String -> IO [[String]] getEdit t name desc serving amounts units ingrs attrs dirs tags = do st <- M.defaultMain (theApp t) (initialState name desc serving amounts units ingrs attrs dirs tags) return [ E.getEditContents $ st^.edit1 , E.getEditContents $ st^.edit2 , E.getEditContents $ st^.edit3 , E.getEditContents $ st^.edit4 , E.getEditContents $ st^.edit5 , E.getEditContents $ st^.edit6 , E.getEditContents $ st^.edit7 , E.getEditContents $ st^.edit8 , E.getEditContents $ st^.edit9 ] getAddInput :: Translator -> IO [[String]] getAddInput t = do st <- M.defaultMain (theApp t) (initialState "" "" "" "" "" "" "" "" "") return [ E.getEditContents $ st^.edit1 , E.getEditContents $ st^.edit2 , E.getEditContents $ st^.edit3 , E.getEditContents $ st^.edit4 , E.getEditContents $ st^.edit5 , E.getEditContents $ st^.edit6 , E.getEditContents $ st^.edit7 , E.getEditContents $ st^.edit8 , E.getEditContents $ st^.edit9 ]