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:
		
							parent
							
								
									788021f5a4
								
							
						
					
					
						commit
						509f55864d
					
				| @ -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 | ||||||
|  | |||||||
| @ -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, | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -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 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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)}} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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} = | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user