ui: indicate real mode and toggle it with R key (#354)

There is a limitation/bug: disabling real mode in the transaction screen
won't show the non-real postings if it was entered from a real-mode
register screen.
This commit is contained in:
Simon Michael 2016-06-01 12:09:16 -07:00
parent 788021f5a4
commit 509f55864d
6 changed files with 78 additions and 29 deletions

View File

@ -24,6 +24,7 @@ module Hledger.Data.Journal (
filterJournalPostings, filterJournalPostings,
filterJournalAmounts, filterJournalAmounts,
filterTransactionAmounts, filterTransactionAmounts,
filterTransactionPostings,
filterPostingAmount, filterPostingAmount,
-- * Querying -- * Querying
journalAccountNames, journalAccountNames,
@ -313,6 +314,10 @@ filterTransactionAmounts q t@Transaction{tpostings=ps} = t{tpostings=map (filter
filterPostingAmount :: Query -> Posting -> Posting filterPostingAmount :: Query -> Posting -> Posting
filterPostingAmount q p@Posting{pamount=Mixed as} = p{pamount=Mixed $ filter (q `matchesAmount`) as} filterPostingAmount q p@Posting{pamount=Mixed as} = p{pamount=Mixed $ filter (q `matchesAmount`) as}
filterTransactionPostings :: Query -> Transaction -> Transaction
filterTransactionPostings m t@Transaction{tpostings=ps} = t{tpostings=filter (m `matchesPosting`) ps}
{- {-
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- filtering V1 -- filtering V1

View File

@ -218,9 +218,6 @@ summarisePostingAccounts ps =
displayps | null realps = ps displayps | null realps = ps
| otherwise = realps | otherwise = realps
filterTransactionPostings :: Query -> Transaction -> Transaction
filterTransactionPostings m t@Transaction{tpostings=ps} = t{tpostings=filter (m `matchesPosting`) ps}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- | Split a transactions report whose items may involve several commodities, -- | Split a transactions report whose items may involve several commodities,

View File

@ -100,13 +100,15 @@ initAccountsScreen d st@AppState{
initAccountsScreen _ _ = error "init function called with wrong screen type, should not happen" initAccountsScreen _ _ = error "init function called with wrong screen type, should not happen"
drawAccountsScreen :: AppState -> [Widget] drawAccountsScreen :: AppState -> [Widget]
drawAccountsScreen _st@AppState{aopts=uopts, ajournal=j, aScreen=AccountsScreen{asState=(l,_)}} = drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
,ajournal=j
,aScreen=AccountsScreen{asState=(l,_)}} =
[ui] [ui]
where where
toplabel = files toplabel = files
<+> str " accounts" <+> str " accounts"
<+> borderQueryStr querystr <+> borderQueryStr querystr
<+> cleared <+> togglefilters
<+> borderDepthStr mdepth <+> borderDepthStr mdepth
<+> str " (" <+> str " ("
<+> cur <+> cur
@ -118,11 +120,15 @@ drawAccountsScreen _st@AppState{aopts=uopts, ajournal=j, aScreen=AccountsScreen{
f:_ -> withAttr ("border" <> "bold") $ str $ takeFileName f f:_ -> withAttr ("border" <> "bold") $ str $ takeFileName f
-- [f,_:[]] -> (withAttr ("border" <> "bold") $ str $ takeFileName f) <+> str " (& 1 included file)" -- [f,_:[]] -> (withAttr ("border" <> "bold") $ str $ takeFileName f) <+> str " (& 1 included file)"
-- f:fs -> (withAttr ("border" <> "bold") $ str $ takeFileName f) <+> str (" (& " ++ show (length fs) ++ " included files)") -- f:fs -> (withAttr ("border" <> "bold") $ str $ takeFileName f) <+> str (" (& " ++ show (length fs) ++ " included files)")
querystr = query_ $ reportopts_ $ cliopts_ uopts querystr = query_ ropts
mdepth = depth_ $ reportopts_ $ cliopts_ uopts mdepth = depth_ ropts
cleared = if (cleared_ $ reportopts_ $ cliopts_ uopts) togglefilters =
then str " with " <+> withAttr (borderAttr <> "query") (str "cleared") <+> str " txns" case concat [
else str "" if cleared_ ropts then ["cleared"] else []
,if real_ ropts then ["real"] else []
] of
[] -> str ""
fs -> str " with " <+> withAttr (borderAttr <> "query") (str $ intercalate ", " fs) <+> str " txns"
cur = str (case l^.listSelectedL of cur = str (case l^.listSelectedL of
Nothing -> "-" Nothing -> "-"
Just i -> show (i + 1)) Just i -> show (i + 1))
@ -133,6 +139,7 @@ drawAccountsScreen _st@AppState{aopts=uopts, ajournal=j, aScreen=AccountsScreen{
("-=1234567890", "depth") ("-=1234567890", "depth")
,("F", "flat?") ,("F", "flat?")
,("C", "cleared?") ,("C", "cleared?")
,("R", "real?")
,("right/enter", "register") ,("right/enter", "register")
,("g", "reload") ,("g", "reload")
,("q", "quit") ,("q", "quit")
@ -249,6 +256,7 @@ handleAccountsScreen st@AppState{
Vty.EvKey (Vty.KChar '0') [] -> continue $ reload j d $ setDepth 0 st' Vty.EvKey (Vty.KChar '0') [] -> continue $ reload j d $ setDepth 0 st'
Vty.EvKey (Vty.KChar 'F') [] -> continue $ reload j d $ stToggleFlat st' Vty.EvKey (Vty.KChar 'F') [] -> continue $ reload j d $ stToggleFlat st'
Vty.EvKey (Vty.KChar 'C') [] -> continue $ reload j d $ stToggleCleared st' Vty.EvKey (Vty.KChar 'C') [] -> continue $ reload j d $ stToggleCleared st'
Vty.EvKey (Vty.KChar 'R') [] -> continue $ reload j d $ stToggleReal st'
Vty.EvKey (Vty.KLeft) [] -> continue $ popScreen st' Vty.EvKey (Vty.KLeft) [] -> continue $ popScreen st'
Vty.EvKey (k) [] | k `elem` [Vty.KRight, Vty.KEnter] -> do Vty.EvKey (k) [] | k `elem` [Vty.KRight, Vty.KEnter] -> do
let let
@ -264,15 +272,6 @@ handleAccountsScreen st@AppState{
-- continue =<< handleEventLensed st' someLens ev -- continue =<< handleEventLensed st' someLens ev
handleAccountsScreen _ _ = error "event handler called with wrong screen type, should not happen" handleAccountsScreen _ _ = error "event handler called with wrong screen type, should not happen"
stToggleFlat :: AppState -> AppState
stToggleFlat st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
st{aopts=uopts{cliopts_=copts{reportopts_=toggleFlatMode ropts}}}
-- | Toggle between flat and tree mode. If in the third "default" mode, go to flat mode.
toggleFlatMode :: ReportOpts -> ReportOpts
toggleFlatMode ropts@ReportOpts{accountlistmode_=ALFlat} = ropts{accountlistmode_=ALTree}
toggleFlatMode ropts = ropts{accountlistmode_=ALFlat}
-- | Get the maximum account depth in the current journal. -- | Get the maximum account depth in the current journal.
maxDepth :: AppState -> Int maxDepth :: AppState -> Int
maxDepth AppState{ajournal=j} = maximum $ map accountNameLevel $ journalAccountNames j maxDepth AppState{ajournal=j} = maximum $ map accountNameLevel $ journalAccountNames j

View File

@ -85,11 +85,11 @@ initRegisterScreen d st@AppState{aopts=opts, ajournal=j, aScreen=s@RegisterScree
initRegisterScreen _ _ = error "init function called with wrong screen type, should not happen" initRegisterScreen _ _ = error "init function called with wrong screen type, should not happen"
drawRegisterScreen :: AppState -> [Widget] drawRegisterScreen :: AppState -> [Widget]
drawRegisterScreen AppState{aopts=uopts -- @UIOpts{cliopts_=_copts@CliOpts{reportopts_=_ropts@ReportOpts{query_=querystr}} drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
,aScreen=RegisterScreen{rsState=(l,acct)}} = [ui] ,aScreen=RegisterScreen{rsState=(l,acct)}} = [ui]
where where
toplabel = withAttr ("border" <> "bold") (str $ T.unpack acct) toplabel = withAttr ("border" <> "bold") (str $ T.unpack acct)
<+> cleared <+> togglefilters
<+> str " transactions" <+> str " transactions"
-- <+> borderQueryStr querystr -- no, account transactions report shows all transactions in the acct ? -- <+> borderQueryStr querystr -- no, account transactions report shows all transactions in the acct ?
-- <+> str " and subs" -- <+> str " and subs"
@ -98,9 +98,13 @@ drawRegisterScreen AppState{aopts=uopts -- @UIOpts{cliopts_=_copts@CliOpts{repor
<+> str "/" <+> str "/"
<+> total <+> total
<+> str ")" <+> str ")"
cleared = if (cleared_ $ reportopts_ $ cliopts_ uopts) togglefilters =
then withAttr (borderAttr <> "query") (str " cleared") case concat [
else str "" if cleared_ ropts then ["cleared"] else []
,if real_ ropts then ["real"] else []
] of
[] -> str ""
fs -> withAttr (borderAttr <> "query") (str $ " " ++ intercalate ", " fs)
cur = str $ case l^.listSelectedL of cur = str $ case l^.listSelectedL of
Nothing -> "-" Nothing -> "-"
Just i -> show (i + 1) Just i -> show (i + 1)
@ -158,6 +162,7 @@ drawRegisterScreen AppState{aopts=uopts -- @UIOpts{cliopts_=_copts@CliOpts{repor
-- ("up/down/pgup/pgdown/home/end", "move") -- ("up/down/pgup/pgdown/home/end", "move")
("left", "back") ("left", "back")
,("C", "cleared?") ,("C", "cleared?")
,("R", "real?")
,("right/enter", "transaction") ,("right/enter", "transaction")
,("g", "reload") ,("g", "reload")
,("q", "quit") ,("q", "quit")
@ -206,6 +211,7 @@ handleRegisterScreen st@AppState{
Left err -> continue $ screenEnter d ES.screen{esState=err} st Left err -> continue $ screenEnter d ES.screen{esState=err} st
Vty.EvKey (Vty.KChar 'C') [] -> continue $ reload j d $ stToggleCleared st Vty.EvKey (Vty.KChar 'C') [] -> continue $ reload j d $ stToggleCleared st
Vty.EvKey (Vty.KChar 'R') [] -> continue $ reload j d $ stToggleReal st
Vty.EvKey (Vty.KLeft) [] -> continue $ popScreen st Vty.EvKey (Vty.KLeft) [] -> continue $ popScreen st

View File

@ -9,7 +9,7 @@ where
-- import Lens.Micro ((^.)) -- import Lens.Micro ((^.))
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
-- import Data.List import Data.List
-- import Data.List.Split (splitOn) -- import Data.List.Split (splitOn)
-- import Data.Ord -- import Data.Ord
import Data.Monoid import Data.Monoid
@ -22,7 +22,7 @@ import Graphics.Vty as Vty
-- import Safe (headDef, lastDef) -- import Safe (headDef, lastDef)
import Brick import Brick
import Brick.Widgets.List (listMoveTo) import Brick.Widgets.List (listMoveTo)
-- import Brick.Widgets.Border import Brick.Widgets.Border (borderAttr)
-- import Brick.Widgets.Border.Style -- import Brick.Widgets.Border.Style
-- import Brick.Widgets.Center -- import Brick.Widgets.Center
-- import Text.Printf -- import Text.Printf
@ -43,12 +43,22 @@ screen = TransactionScreen{
} }
initTransactionScreen :: Day -> AppState -> AppState initTransactionScreen :: Day -> AppState -> AppState
initTransactionScreen _d st@AppState{aopts=_opts, ajournal=_j, aScreen=_s@TransactionScreen{tsState=_}} = st initTransactionScreen d st@AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
,ajournal=_j
,aScreen=s@TransactionScreen{tsState=((n,t),nts,a)}} =
st{aScreen=s{tsState=((n, t'),nts,a)}}
where
-- re-filter the postings, eg because real/virtual was toggled.
-- get the original transaction from the list passed from the register screen.
t' = case lookup n nts of
Just torig -> filterTransactionPostings (queryFromOpts d ropts) torig
Nothing -> t -- shouldn't happen
initTransactionScreen _ _ = error "init function called with wrong screen type, should not happen" initTransactionScreen _ _ = error "init function called with wrong screen type, should not happen"
drawTransactionScreen :: AppState -> [Widget] drawTransactionScreen :: AppState -> [Widget]
drawTransactionScreen AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reportopts_=_ropts@ReportOpts{query_=querystr}}}, drawTransactionScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
aScreen=TransactionScreen{tsState=((i,t),nts,acct)}} = [ui] ,aScreen=TransactionScreen{tsState=((i,t),nts,acct)}} = [ui]
where where
-- datedesc = show (tdate t) ++ " " ++ tdescription t -- datedesc = show (tdate t) ++ " " ++ tdescription t
toplabel = toplabel =
@ -59,9 +69,18 @@ drawTransactionScreen AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{r
<+> str " (" <+> str " ("
<+> withAttr ("border" <> "bold") (str $ show i) <+> withAttr ("border" <> "bold") (str $ show i)
<+> str (" of "++show (length nts)++" in "++T.unpack acct++")") <+> str (" of "++show (length nts)++" in "++T.unpack acct++")")
<+> togglefilters
togglefilters =
case concat [
if cleared_ ropts then ["cleared"] else []
,if real_ ropts then ["real"] else []
] of
[] -> str ""
fs -> withAttr (borderAttr <> "query") (str $ " " ++ intercalate ", " fs) <+> str " postings"
bottomlabel = borderKeysStr [ bottomlabel = borderKeysStr [
("left", "back") ("left", "back")
,("up/down", "prev/next") ,("up/down", "prev/next")
,("R", "real?")
,("g", "reload") ,("g", "reload")
,("q", "quit") ,("q", "quit")
] ]
@ -114,6 +133,10 @@ handleTransactionScreen st@AppState{
-- Vty.EvKey (Vty.KChar 'C') [] -> continue $ reload j d $ stToggleCleared st -- Vty.EvKey (Vty.KChar 'C') [] -> continue $ reload j d $ stToggleCleared st
Vty.EvKey (Vty.KChar 'R') [] ->
-- just show/hide the real postings in this transaction, don't bother updating parent screens
continue $ reload j d $ stToggleReal st
Vty.EvKey (Vty.KUp) [] -> continue $ reload j d st{aScreen=s{tsState=((iprev,tprev),nts,acct)}} Vty.EvKey (Vty.KUp) [] -> continue $ reload j d st{aScreen=s{tsState=((iprev,tprev),nts,acct)}}
Vty.EvKey (Vty.KDown) [] -> continue $ reload j d st{aScreen=s{tsState=((inext,tnext),nts,acct)}} Vty.EvKey (Vty.KDown) [] -> continue $ reload j d st{aScreen=s{tsState=((inext,tnext),nts,acct)}}

View File

@ -16,6 +16,8 @@ module Hledger.UI.UIUtils (
,borderKeysStr ,borderKeysStr
-- --
,stToggleCleared ,stToggleCleared
,stToggleFlat
,stToggleReal
) where ) where
import Lens.Micro ((^.)) import Lens.Micro ((^.))
@ -47,6 +49,23 @@ stToggleCleared st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts
toggleCleared :: ReportOpts -> ReportOpts toggleCleared :: ReportOpts -> ReportOpts
toggleCleared ropts = ropts{cleared_=not $ cleared_ ropts} toggleCleared ropts = ropts{cleared_=not $ cleared_ ropts}
stToggleFlat :: AppState -> AppState
stToggleFlat st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
st{aopts=uopts{cliopts_=copts{reportopts_=toggleFlatMode ropts}}}
-- | Toggle between flat and tree mode. If in the third "default" mode, go to flat mode.
toggleFlatMode :: ReportOpts -> ReportOpts
toggleFlatMode ropts@ReportOpts{accountlistmode_=ALFlat} = ropts{accountlistmode_=ALTree}
toggleFlatMode ropts = ropts{accountlistmode_=ALFlat}
stToggleReal :: AppState -> AppState
stToggleReal st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
st{aopts=uopts{cliopts_=copts{reportopts_=toggleReal ropts}}}
-- | Toggle between showing all and showing only real (non-virtual) items.
toggleReal :: ReportOpts -> ReportOpts
toggleReal ropts = ropts{real_=not $ real_ ropts}
-- | Regenerate the content for the current and previous screens, from a new journal and current date. -- | Regenerate the content for the current and previous screens, from a new journal and current date.
reload :: Journal -> Day -> AppState -> AppState reload :: Journal -> Day -> AppState -> AppState
reload j d st@AppState{aScreen=s,aPrevScreens=ss} = reload j d st@AppState{aScreen=s,aPrevScreens=ss} =