ui: convert screen states to records
This is highly verbose, but potentially clearer, allows better haddock docs, and hopefully will improve after lensification.
This commit is contained in:
parent
5259605e82
commit
5c343a5848
@ -41,36 +41,38 @@ import Hledger.UI.ErrorScreen
|
|||||||
|
|
||||||
accountsScreen :: Screen
|
accountsScreen :: Screen
|
||||||
accountsScreen = AccountsScreen{
|
accountsScreen = AccountsScreen{
|
||||||
asState = (list "accounts" V.empty 1, "")
|
asState = AccountsScreenState{asItems=list "accounts" V.empty 1
|
||||||
|
,asSelectedAccount=""
|
||||||
|
}
|
||||||
,sInitFn = initAccountsScreen
|
,sInitFn = initAccountsScreen
|
||||||
,sDrawFn = drawAccountsScreen
|
,sDrawFn = drawAccountsScreen
|
||||||
,sHandleFn = handleAccountsScreen
|
,sHandleFn = handleAccountsScreen
|
||||||
}
|
}
|
||||||
|
|
||||||
asSetSelectedAccount a scr@AccountsScreen{asState=(l,_)} = scr{asState=(l,a)}
|
asSetSelectedAccount a scr@AccountsScreen{asState=st} = scr{asState=st{asSelectedAccount=a}}
|
||||||
asSetSelectedAccount _ scr = scr
|
asSetSelectedAccount _ scr = scr
|
||||||
|
|
||||||
initAccountsScreen :: Day -> Bool -> AppState -> AppState
|
initAccountsScreen :: Day -> Bool -> AppState -> AppState
|
||||||
initAccountsScreen d reset st@AppState{
|
initAccountsScreen d reset st@AppState{
|
||||||
aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}},
|
aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}},
|
||||||
ajournal=j,
|
ajournal=j,
|
||||||
aScreen=s@AccountsScreen{asState=(oldl,selacct)}
|
aScreen=s@AccountsScreen{asState=asState@AccountsScreenState{..}}
|
||||||
} =
|
} =
|
||||||
st{aopts=uopts', aScreen=s{asState=(newl',selacct)}}
|
st{aopts=uopts', aScreen=s{asState=asState{asItems=newitems'}}}
|
||||||
where
|
where
|
||||||
newl = list (Name "accounts") (V.fromList displayitems) 1
|
newitems = list (Name "accounts") (V.fromList displayitems) 1
|
||||||
|
|
||||||
-- keep the selection near the last selected account
|
-- keep the selection near the last selected account
|
||||||
-- (may need to move to the next leaf account when entering flat mode)
|
-- (may need to move to the next leaf account when entering flat mode)
|
||||||
newl' = listMoveTo selidx newl
|
newitems' = listMoveTo selidx newitems
|
||||||
where
|
where
|
||||||
selidx = case (reset, listSelectedElement oldl) of
|
selidx = case (reset, listSelectedElement asItems) of
|
||||||
(True, _) -> 0
|
(True, _) -> 0
|
||||||
(_, Nothing) -> 0
|
(_, Nothing) -> 0
|
||||||
(_, Just (_,(_,a,_,_))) -> fromMaybe (fromMaybe 0 mprefixmatch) mexactmatch
|
(_, Just (_,AccountsScreenItem{asItemAccountName=a})) -> fromMaybe (fromMaybe 0 mprefixmatch) mexactmatch
|
||||||
where
|
where
|
||||||
mexactmatch = findIndex ((a ==) . second4) displayitems
|
mexactmatch = findIndex ((a ==) . asItemAccountName) displayitems
|
||||||
mprefixmatch = findIndex ((a `isAccountNamePrefixOf`) . second4) displayitems
|
mprefixmatch = findIndex ((a `isAccountNamePrefixOf`) . asItemAccountName) displayitems
|
||||||
uopts' = uopts{cliopts_=copts{reportopts_=ropts'}}
|
uopts' = uopts{cliopts_=copts{reportopts_=ropts'}}
|
||||||
ropts' = ropts {
|
ropts' = ropts {
|
||||||
-- XXX balanceReport doesn't respect this yet
|
-- XXX balanceReport doesn't respect this yet
|
||||||
@ -90,11 +92,11 @@ initAccountsScreen d reset st@AppState{
|
|||||||
|
|
||||||
-- pre-render the list items
|
-- pre-render the list items
|
||||||
displayitem ((fullacct, shortacct, indent), bal) =
|
displayitem ((fullacct, shortacct, indent), bal) =
|
||||||
(indent
|
AccountsScreenItem{asItemIndentLevel = indent
|
||||||
,fullacct
|
,asItemAccountName = fullacct
|
||||||
,if flat_ ropts' then fullacct else shortacct
|
,asItemDisplayAccountName = if flat_ ropts' then fullacct else shortacct
|
||||||
,map showAmountWithoutPrice amts -- like showMixedAmountOneLineWithoutPrice
|
,asItemRenderedAmounts = map showAmountWithoutPrice amts -- like showMixedAmountOneLineWithoutPrice
|
||||||
)
|
}
|
||||||
where
|
where
|
||||||
Mixed amts = normaliseMixedAmountSquashPricesForDisplay $ stripPrices bal
|
Mixed amts = normaliseMixedAmountSquashPricesForDisplay $ stripPrices bal
|
||||||
stripPrices (Mixed as) = Mixed $ map stripprice as where stripprice a = a{aprice=NoPrice}
|
stripPrices (Mixed as) = Mixed $ map stripprice as where stripprice a = a{aprice=NoPrice}
|
||||||
@ -106,7 +108,7 @@ initAccountsScreen _ _ _ = error "init function called with wrong screen type, s
|
|||||||
drawAccountsScreen :: AppState -> [Widget]
|
drawAccountsScreen :: AppState -> [Widget]
|
||||||
drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
||||||
,ajournal=j
|
,ajournal=j
|
||||||
,aScreen=AccountsScreen{asState=(l,_)}
|
,aScreen=AccountsScreen{asState=AccountsScreenState{..}}
|
||||||
,aMinibuffer=mbuf} =
|
,aMinibuffer=mbuf} =
|
||||||
[ui]
|
[ui]
|
||||||
where
|
where
|
||||||
@ -139,10 +141,10 @@ drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
|||||||
fs -> str " with " <+> withAttr (borderAttr <> "query") (str $ intercalate ", " fs) <+> str " txns"
|
fs -> str " with " <+> withAttr (borderAttr <> "query") (str $ intercalate ", " fs) <+> str " txns"
|
||||||
nonzero | empty_ ropts = str ""
|
nonzero | empty_ ropts = str ""
|
||||||
| otherwise = withAttr (borderAttr <> "query") (str " nonzero")
|
| otherwise = withAttr (borderAttr <> "query") (str " nonzero")
|
||||||
cur = str (case l^.listSelectedL of
|
cur = str (case asItems ^. listSelectedL of
|
||||||
Nothing -> "-"
|
Nothing -> "-"
|
||||||
Just i -> show (i + 1))
|
Just i -> show (i + 1))
|
||||||
total = str $ show $ V.length $ l^.listElementsL
|
total = str $ show $ V.length $ asItems ^. listElementsL
|
||||||
|
|
||||||
bottomlabel = borderKeysStr [
|
bottomlabel = borderKeysStr [
|
||||||
-- ("up/down/pgup/pgdown/home/end", "move")
|
-- ("up/down/pgup/pgdown/home/end", "move")
|
||||||
@ -171,16 +173,16 @@ drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
|||||||
-- ltrace "availwidth" $
|
-- ltrace "availwidth" $
|
||||||
c^.availWidthL
|
c^.availWidthL
|
||||||
- 2 -- XXX due to margin ? shouldn't be necessary (cf UIUtils)
|
- 2 -- XXX due to margin ? shouldn't be necessary (cf UIUtils)
|
||||||
displayitems = listElements l
|
displayitems = listElements asItems
|
||||||
maxacctwidthseen =
|
maxacctwidthseen =
|
||||||
-- ltrace "maxacctwidthseen" $
|
-- ltrace "maxacctwidthseen" $
|
||||||
V.maximum $
|
V.maximum $
|
||||||
V.map (\(indent,_,displayacct,_) -> indent*2 + textWidth displayacct) $
|
V.map (\AccountsScreenItem{..} -> asItemIndentLevel*2 + textWidth asItemDisplayAccountName) $
|
||||||
-- V.filter (\(indent,_,_,_) -> (indent-1) <= fromMaybe 99999 mdepth) $
|
-- V.filter (\(indent,_,_,_) -> (indent-1) <= fromMaybe 99999 mdepth) $
|
||||||
displayitems
|
displayitems
|
||||||
maxbalwidthseen =
|
maxbalwidthseen =
|
||||||
-- ltrace "maxbalwidthseen" $
|
-- ltrace "maxbalwidthseen" $
|
||||||
V.maximum $ V.map (\(_,_,_,amts) -> sum (map strWidth amts) + 2 * (length amts-1)) displayitems
|
V.maximum $ V.map (\AccountsScreenItem{..} -> sum (map strWidth asItemRenderedAmounts) + 2 * (length asItemRenderedAmounts - 1)) displayitems
|
||||||
maxbalwidth =
|
maxbalwidth =
|
||||||
-- ltrace "maxbalwidth" $
|
-- ltrace "maxbalwidth" $
|
||||||
max 0 (availwidth - 2 - 4) -- leave 2 whitespace plus least 4 for accts
|
max 0 (availwidth - 2 - 4) -- leave 2 whitespace plus least 4 for accts
|
||||||
@ -199,20 +201,20 @@ drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
|||||||
|
|
||||||
colwidths = (acctwidth, balwidth)
|
colwidths = (acctwidth, balwidth)
|
||||||
|
|
||||||
render $ defaultLayout toplabel bottomarea $ renderList l (drawAccountsItem colwidths)
|
render $ defaultLayout toplabel bottomarea $ renderList asItems (drawAccountsItem colwidths)
|
||||||
|
|
||||||
drawAccountsScreen _ = error "draw function called with wrong screen type, should not happen"
|
drawAccountsScreen _ = error "draw function called with wrong screen type, should not happen"
|
||||||
|
|
||||||
drawAccountsItem :: (Int,Int) -> Bool -> (Int, AccountName, AccountName, [String]) -> Widget
|
drawAccountsItem :: (Int,Int) -> Bool -> AccountsScreenItem -> Widget
|
||||||
drawAccountsItem (acctwidth, balwidth) selected (indent, _fullacct, displayacct, balamts) =
|
drawAccountsItem (acctwidth, balwidth) selected AccountsScreenItem{..} =
|
||||||
Widget Greedy Fixed $ do
|
Widget Greedy Fixed $ do
|
||||||
-- c <- getContext
|
-- c <- getContext
|
||||||
-- let showitem = intercalate "\n" . balanceReportItemAsText defreportopts fmt
|
-- let showitem = intercalate "\n" . balanceReportItemAsText defreportopts fmt
|
||||||
render $
|
render $
|
||||||
addamts balamts $
|
addamts asItemRenderedAmounts $
|
||||||
str (T.unpack $ fitText (Just acctwidth) (Just acctwidth) True True $ T.replicate (2*indent) " " <> displayacct) <+>
|
str (T.unpack $ fitText (Just acctwidth) (Just acctwidth) True True $ T.replicate (2*asItemIndentLevel) " " <> asItemDisplayAccountName) <+>
|
||||||
str " " <+>
|
str " " <+>
|
||||||
str (balspace balamts)
|
str (balspace asItemRenderedAmounts)
|
||||||
where
|
where
|
||||||
balspace as = replicate n ' '
|
balspace as = replicate n ' '
|
||||||
where n = max 0 (balwidth - (sum (map strWidth as) + 2 * (length as - 1)))
|
where n = max 0 (balwidth - (sum (map strWidth as) + 2 * (length as - 1)))
|
||||||
@ -232,7 +234,7 @@ drawAccountsItem (acctwidth, balwidth) selected (indent, _fullacct, displayacct,
|
|||||||
|
|
||||||
handleAccountsScreen :: AppState -> Vty.Event -> EventM (Next AppState)
|
handleAccountsScreen :: AppState -> Vty.Event -> EventM (Next AppState)
|
||||||
handleAccountsScreen st@AppState{
|
handleAccountsScreen st@AppState{
|
||||||
aScreen=scr@AccountsScreen{asState=(l,selacct)}
|
aScreen=scr@AccountsScreen{asState=asState@AccountsScreenState{..}}
|
||||||
,aopts=UIOpts{cliopts_=copts}
|
,aopts=UIOpts{cliopts_=copts}
|
||||||
,ajournal=j
|
,ajournal=j
|
||||||
,aMinibuffer=mbuf
|
,aMinibuffer=mbuf
|
||||||
@ -245,10 +247,10 @@ handleAccountsScreen st@AppState{
|
|||||||
-- before we go anywhere, remember the currently selected account.
|
-- before we go anywhere, remember the currently selected account.
|
||||||
-- (This is preserved across screen changes, unlike List's selection state)
|
-- (This is preserved across screen changes, unlike List's selection state)
|
||||||
let
|
let
|
||||||
selacct' = case listSelectedElement l of
|
selacct = case listSelectedElement asItems of
|
||||||
Just (_, (_, fullacct, _, _)) -> fullacct
|
Just (_, AccountsScreenItem{..}) -> asItemAccountName
|
||||||
Nothing -> selacct
|
Nothing -> asSelectedAccount
|
||||||
st' = st{aScreen=scr{asState=(l,selacct')}}
|
st' = st{aScreen=scr{asState=asState{asSelectedAccount=selacct}}}
|
||||||
|
|
||||||
case mbuf of
|
case mbuf of
|
||||||
Nothing ->
|
Nothing ->
|
||||||
@ -281,15 +283,15 @@ handleAccountsScreen st@AppState{
|
|||||||
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
|
||||||
scr = rsSetCurrentAccount selacct' registerScreen
|
scr = rsSetCurrentAccount selacct registerScreen
|
||||||
st'' = screenEnter d scr st'
|
st'' = screenEnter d scr st'
|
||||||
scrollTopRegister
|
scrollTopRegister
|
||||||
continue st''
|
continue st''
|
||||||
|
|
||||||
-- fall through to the list's event handler (handles up/down)
|
-- fall through to the list's event handler (handles up/down)
|
||||||
ev -> do
|
ev -> do
|
||||||
l' <- handleEvent ev l
|
newitems <- handleEvent ev asItems
|
||||||
continue $ st'{aScreen=scr{asState=(l',selacct')}}
|
continue $ st'{aScreen=scr{asState=asState{asItems=newitems,asSelectedAccount=selacct}}}
|
||||||
-- continue =<< handleEventLensed st' someLens ev
|
-- continue =<< handleEventLensed st' someLens ev
|
||||||
|
|
||||||
Just ed ->
|
Just ed ->
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
-- The error screen, showing a current error condition (such as a parse error after reloading the journal)
|
-- The error screen, showing a current error condition (such as a parse error after reloading the journal)
|
||||||
|
|
||||||
{-# LANGUAGE OverloadedStrings, FlexibleContexts #-}
|
{-# LANGUAGE OverloadedStrings, FlexibleContexts, RecordWildCards #-}
|
||||||
|
|
||||||
module Hledger.UI.ErrorScreen
|
module Hledger.UI.ErrorScreen
|
||||||
(errorScreen
|
(errorScreen
|
||||||
@ -30,7 +30,7 @@ import Hledger.UI.UIUtils
|
|||||||
|
|
||||||
errorScreen :: Screen
|
errorScreen :: Screen
|
||||||
errorScreen = ErrorScreen{
|
errorScreen = ErrorScreen{
|
||||||
esState = ""
|
esState = ErrorScreenState{esError=""}
|
||||||
,sInitFn = initErrorScreen
|
,sInitFn = initErrorScreen
|
||||||
,sDrawFn = drawErrorScreen
|
,sDrawFn = drawErrorScreen
|
||||||
,sHandleFn = handleErrorScreen
|
,sHandleFn = handleErrorScreen
|
||||||
@ -42,7 +42,7 @@ initErrorScreen _ _ _ = error "init function called with wrong screen type, shou
|
|||||||
|
|
||||||
drawErrorScreen :: AppState -> [Widget]
|
drawErrorScreen :: AppState -> [Widget]
|
||||||
drawErrorScreen AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reportopts_=_ropts@ReportOpts{query_=querystr}}},
|
drawErrorScreen AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reportopts_=_ropts@ReportOpts{query_=querystr}}},
|
||||||
aScreen=ErrorScreen{esState=err}} = [ui]
|
aScreen=ErrorScreen{esState=ErrorScreenState{..}}} = [ui]
|
||||||
where
|
where
|
||||||
toplabel = withAttr ("border" <> "bold") (str "Oops. Please fix this problem then press g to reload")
|
toplabel = withAttr ("border" <> "bold") (str "Oops. Please fix this problem then press g to reload")
|
||||||
-- <+> str " transactions"
|
-- <+> str " transactions"
|
||||||
@ -75,7 +75,7 @@ drawErrorScreen AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reporto
|
|||||||
-- totalwidth = c^.availWidthL
|
-- totalwidth = c^.availWidthL
|
||||||
-- - 2 -- XXX due to margin ? shouldn't be necessary (cf UIUtils)
|
-- - 2 -- XXX due to margin ? shouldn't be necessary (cf UIUtils)
|
||||||
|
|
||||||
render $ defaultLayout toplabel bottomlabel $ withAttr "error" $ str err
|
render $ defaultLayout toplabel bottomlabel $ withAttr "error" $ str $ esError
|
||||||
|
|
||||||
drawErrorScreen _ = error "draw function called with wrong screen type, should not happen"
|
drawErrorScreen _ = error "draw function called with wrong screen type, should not happen"
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ handleErrorScreen st@AppState{
|
|||||||
Vty.EvKey (Vty.KChar 'g') [] -> do
|
Vty.EvKey (Vty.KChar 'g') [] -> do
|
||||||
(ej, _) <- liftIO $ journalReloadIfChanged copts d j
|
(ej, _) <- liftIO $ journalReloadIfChanged copts d j
|
||||||
case ej of
|
case ej of
|
||||||
Left err -> continue st{aScreen=s{esState=err}} -- show latest parse error
|
Left err -> continue st{aScreen=s{esState=ErrorScreenState{esError=err}}} -- show latest parse error
|
||||||
Right j' -> continue $ regenerateScreens j' d $ popScreen st -- return to previous screen, and reload it
|
Right j' -> continue $ regenerateScreens j' d $ popScreen st -- return to previous screen, and reload it
|
||||||
|
|
||||||
-- Vty.EvKey (Vty.KLeft) [] -> continue $ popScreen st
|
-- Vty.EvKey (Vty.KLeft) [] -> continue $ popScreen st
|
||||||
@ -133,5 +133,5 @@ stReloadJournalIfChanged copts d j st = do
|
|||||||
(ej, _) <- journalReloadIfChanged copts d j
|
(ej, _) <- journalReloadIfChanged copts d j
|
||||||
return $ case ej of
|
return $ case ej of
|
||||||
Right j' -> regenerateScreens j' d st
|
Right j' -> regenerateScreens j' d st
|
||||||
Left err -> screenEnter d errorScreen{esState=err} st
|
Left err -> screenEnter d errorScreen{esState=ErrorScreenState{esError=err}} st
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
-- The account register screen, showing transactions in an account, like hledger-web's register.
|
-- The account register screen, showing transactions in an account, like hledger-web's register.
|
||||||
|
|
||||||
{-# LANGUAGE OverloadedStrings, FlexibleContexts #-}
|
{-# LANGUAGE OverloadedStrings, FlexibleContexts, RecordWildCards #-}
|
||||||
|
|
||||||
module Hledger.UI.RegisterScreen
|
module Hledger.UI.RegisterScreen
|
||||||
(registerScreen
|
(registerScreen
|
||||||
@ -37,18 +37,20 @@ import Hledger.UI.ErrorScreen
|
|||||||
|
|
||||||
registerScreen :: Screen
|
registerScreen :: Screen
|
||||||
registerScreen = RegisterScreen{
|
registerScreen = RegisterScreen{
|
||||||
rsState = (list "register" V.empty 1, "")
|
rsState = RegisterScreenState{rsItems=list "register" V.empty 1
|
||||||
|
,rsSelectedAccount=""
|
||||||
|
}
|
||||||
,sInitFn = initRegisterScreen
|
,sInitFn = initRegisterScreen
|
||||||
,sDrawFn = drawRegisterScreen
|
,sDrawFn = drawRegisterScreen
|
||||||
,sHandleFn = handleRegisterScreen
|
,sHandleFn = handleRegisterScreen
|
||||||
}
|
}
|
||||||
|
|
||||||
rsSetCurrentAccount a scr@RegisterScreen{rsState=(l,_)} = scr{rsState=(l,a)}
|
rsSetCurrentAccount a scr@RegisterScreen{..} = scr{rsState=rsState{rsSelectedAccount=a}}
|
||||||
rsSetCurrentAccount _ scr = scr
|
rsSetCurrentAccount _ scr = scr
|
||||||
|
|
||||||
initRegisterScreen :: Day -> Bool -> AppState -> AppState
|
initRegisterScreen :: Day -> Bool -> AppState -> AppState
|
||||||
initRegisterScreen d reset st@AppState{aopts=opts, ajournal=j, aScreen=s@RegisterScreen{rsState=(oldl,acct)}} =
|
initRegisterScreen d reset st@AppState{aopts=opts, ajournal=j, aScreen=s@RegisterScreen{rsState=rsState@RegisterScreenState{..}}} =
|
||||||
st{aScreen=s{rsState=(newl',acct)}}
|
st{aScreen=s{rsState=rsState{rsItems=newitems'}}}
|
||||||
where
|
where
|
||||||
-- gather arguments and queries
|
-- gather arguments and queries
|
||||||
ropts = (reportopts_ $ cliopts_ opts)
|
ropts = (reportopts_ $ cliopts_ opts)
|
||||||
@ -57,7 +59,7 @@ initRegisterScreen d reset st@AppState{aopts=opts, ajournal=j, aScreen=s@Registe
|
|||||||
balancetype_=HistoricalBalance
|
balancetype_=HistoricalBalance
|
||||||
}
|
}
|
||||||
-- XXX temp
|
-- XXX temp
|
||||||
thisacctq = Acct $ accountNameToAccountRegex acct -- includes subs
|
thisacctq = Acct $ accountNameToAccountRegex rsSelectedAccount -- includes subs
|
||||||
q = filterQuery (not . queryIsDepth) $ queryFromOpts d ropts
|
q = filterQuery (not . queryIsDepth) $ queryFromOpts d ropts
|
||||||
|
|
||||||
(_label,items) = accountTransactionsReport ropts j q thisacctq
|
(_label,items) = accountTransactionsReport ropts j q thisacctq
|
||||||
@ -65,43 +67,44 @@ initRegisterScreen d reset st@AppState{aopts=opts, ajournal=j, aScreen=s@Registe
|
|||||||
reverse -- most recent last
|
reverse -- most recent last
|
||||||
items
|
items
|
||||||
|
|
||||||
-- pre-render all items; these will be the List elements. This helps calculate column widths.
|
-- generate pre-rendered list items. This helps calculate column widths.
|
||||||
displayitems = map displayitem items'
|
displayitems = map displayitem items'
|
||||||
where
|
where
|
||||||
displayitem (t, _, _issplit, otheracctsstr, change, bal) =
|
displayitem (t, _, _issplit, otheracctsstr, change, bal) =
|
||||||
(showDate $ tdate t
|
RegisterScreenItem{rsItemDate = showDate $ tdate t
|
||||||
,T.unpack $ tdescription t
|
,rsItemDescription = T.unpack $ tdescription t
|
||||||
,case splitOn ", " otheracctsstr of
|
,rsItemOtherAccounts = case splitOn ", " otheracctsstr of
|
||||||
[s] -> s
|
[s] -> s
|
||||||
ss -> intercalate ", " ss
|
ss -> intercalate ", " ss
|
||||||
-- _ -> "<split>" -- should do this if accounts field width < 30
|
-- _ -> "<split>" -- should do this if accounts field width < 30
|
||||||
,showMixedAmountOneLineWithoutPrice change
|
,rsItemChangeAmount = showMixedAmountOneLineWithoutPrice change
|
||||||
,showMixedAmountOneLineWithoutPrice bal
|
,rsItemBalanceAmount = showMixedAmountOneLineWithoutPrice bal
|
||||||
,t
|
,rsItemTransaction = t
|
||||||
)
|
}
|
||||||
|
|
||||||
-- build the List
|
-- build the List
|
||||||
newl = list (Name "register") (V.fromList displayitems) 1
|
newitems = list (Name "register") (V.fromList displayitems) 1
|
||||||
|
|
||||||
-- keep the selection on the previously selected transaction if possible,
|
-- keep the selection on the previously selected transaction if possible,
|
||||||
-- (eg after toggling nonzero mode), otherwise select the last element.
|
-- (eg after toggling nonzero mode), otherwise select the last element.
|
||||||
newl' = listMoveTo newselidx newl
|
newitems' = listMoveTo newselidx newitems
|
||||||
where
|
where
|
||||||
newselidx = case (reset, listSelectedElement oldl) of
|
newselidx = case (reset, listSelectedElement rsItems) of
|
||||||
(True, _) -> 0
|
(True, _) -> 0
|
||||||
(_, Nothing) -> endidx
|
(_, Nothing) -> endidx
|
||||||
(_, Just (_,(_,_,_,_,_,Transaction{tindex=ti}))) -> fromMaybe endidx $ findIndex ((==ti) . tindex . sixth6) displayitems
|
(_, Just (_,RegisterScreenItem{rsItemTransaction=Transaction{tindex=ti}}))
|
||||||
|
-> fromMaybe endidx $ findIndex ((==ti) . tindex . rsItemTransaction) displayitems
|
||||||
endidx = length displayitems
|
endidx = length displayitems
|
||||||
|
|
||||||
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=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
||||||
,aScreen=RegisterScreen{rsState=(l,acct)}
|
,aScreen=RegisterScreen{rsState=RegisterScreenState{..}}
|
||||||
,aMinibuffer=mbuf}
|
,aMinibuffer=mbuf}
|
||||||
= [ui]
|
= [ui]
|
||||||
where
|
where
|
||||||
toplabel = withAttr ("border" <> "bold") (str $ T.unpack acct)
|
toplabel = withAttr ("border" <> "bold") (str $ T.unpack rsSelectedAccount)
|
||||||
<+> togglefilters
|
<+> togglefilters
|
||||||
<+> str " transactions"
|
<+> str " transactions"
|
||||||
<+> borderQueryStr (query_ ropts)
|
<+> borderQueryStr (query_ ropts)
|
||||||
@ -121,11 +124,11 @@ drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
|||||||
] of
|
] of
|
||||||
[] -> str ""
|
[] -> str ""
|
||||||
fs -> withAttr (borderAttr <> "query") (str $ " " ++ intercalate ", " fs)
|
fs -> withAttr (borderAttr <> "query") (str $ " " ++ intercalate ", " fs)
|
||||||
cur = str $ case l^.listSelectedL of
|
cur = str $ case rsItems ^. listSelectedL of
|
||||||
Nothing -> "-"
|
Nothing -> "-"
|
||||||
Just i -> show (i + 1)
|
Just i -> show (i + 1)
|
||||||
total = str $ show $ length displayitems
|
total = str $ show $ length displayitems
|
||||||
displayitems = V.toList $ l^.listElementsL
|
displayitems = V.toList $ rsItems ^. listElementsL
|
||||||
|
|
||||||
-- query = query_ $ reportopts_ $ cliopts_ opts
|
-- query = query_ $ reportopts_ $ cliopts_ opts
|
||||||
|
|
||||||
@ -148,8 +151,8 @@ drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
|||||||
whitespacewidth = 10 -- inter-column whitespace, fixed width
|
whitespacewidth = 10 -- inter-column whitespace, fixed width
|
||||||
minnonamtcolswidth = datewidth + 2 + 2 -- date column plus at least 2 for desc and accts
|
minnonamtcolswidth = datewidth + 2 + 2 -- date column plus at least 2 for desc and accts
|
||||||
maxamtswidth = max 0 (totalwidth - minnonamtcolswidth - whitespacewidth)
|
maxamtswidth = max 0 (totalwidth - minnonamtcolswidth - whitespacewidth)
|
||||||
maxchangewidthseen = maximum' $ map (strWidth . fourth6) displayitems
|
maxchangewidthseen = maximum' $ map (strWidth . rsItemChangeAmount) displayitems
|
||||||
maxbalwidthseen = maximum' $ map (strWidth . fifth6) displayitems
|
maxbalwidthseen = maximum' $ map (strWidth . rsItemBalanceAmount) displayitems
|
||||||
changewidthproportion = fromIntegral maxchangewidthseen / fromIntegral (maxchangewidthseen + maxbalwidthseen)
|
changewidthproportion = fromIntegral maxchangewidthseen / fromIntegral (maxchangewidthseen + maxbalwidthseen)
|
||||||
maxchangewidth = round $ changewidthproportion * fromIntegral maxamtswidth
|
maxchangewidth = round $ changewidthproportion * fromIntegral maxamtswidth
|
||||||
maxbalwidth = maxamtswidth - maxchangewidth
|
maxbalwidth = maxamtswidth - maxchangewidth
|
||||||
@ -193,34 +196,34 @@ drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
|||||||
Nothing -> bottomlabel
|
Nothing -> bottomlabel
|
||||||
Just ed -> minibuffer ed
|
Just ed -> minibuffer ed
|
||||||
|
|
||||||
render $ defaultLayout toplabel bottomarea $ renderList l (drawRegisterItem colwidths)
|
render $ defaultLayout toplabel bottomarea $ renderList rsItems (drawRegisterItem colwidths)
|
||||||
|
|
||||||
drawRegisterScreen _ = error "draw function called with wrong screen type, should not happen"
|
drawRegisterScreen _ = error "draw function called with wrong screen type, should not happen"
|
||||||
|
|
||||||
drawRegisterItem :: (Int,Int,Int,Int,Int) -> Bool -> (String,String,String,String,String,Transaction) -> Widget
|
drawRegisterItem :: (Int,Int,Int,Int,Int) -> Bool -> RegisterScreenItem -> Widget
|
||||||
drawRegisterItem (datewidth,descwidth,acctswidth,changewidth,balwidth) selected (date,desc,accts,change,bal,_) =
|
drawRegisterItem (datewidth,descwidth,acctswidth,changewidth,balwidth) selected RegisterScreenItem{..} =
|
||||||
Widget Greedy Fixed $ do
|
Widget Greedy Fixed $ do
|
||||||
render $
|
render $
|
||||||
str (fitString (Just datewidth) (Just datewidth) True True date) <+>
|
str (fitString (Just datewidth) (Just datewidth) True True rsItemDate) <+>
|
||||||
str " " <+>
|
str " " <+>
|
||||||
str (fitString (Just descwidth) (Just descwidth) True True desc) <+>
|
str (fitString (Just descwidth) (Just descwidth) True True rsItemDescription) <+>
|
||||||
str " " <+>
|
str " " <+>
|
||||||
str (fitString (Just acctswidth) (Just acctswidth) True True accts) <+>
|
str (fitString (Just acctswidth) (Just acctswidth) True True rsItemOtherAccounts) <+>
|
||||||
str " " <+>
|
str " " <+>
|
||||||
withAttr changeattr (str (fitString (Just changewidth) (Just changewidth) True False change)) <+>
|
withAttr changeattr (str (fitString (Just changewidth) (Just changewidth) True False rsItemChangeAmount)) <+>
|
||||||
str " " <+>
|
str " " <+>
|
||||||
withAttr balattr (str (fitString (Just balwidth) (Just balwidth) True False bal))
|
withAttr balattr (str (fitString (Just balwidth) (Just balwidth) True False rsItemBalanceAmount))
|
||||||
where
|
where
|
||||||
changeattr | '-' `elem` change = sel $ "list" <> "amount" <> "decrease"
|
changeattr | '-' `elem` rsItemChangeAmount = sel $ "list" <> "amount" <> "decrease"
|
||||||
| otherwise = sel $ "list" <> "amount" <> "increase"
|
| otherwise = sel $ "list" <> "amount" <> "increase"
|
||||||
balattr | '-' `elem` bal = sel $ "list" <> "balance" <> "negative"
|
balattr | '-' `elem` rsItemBalanceAmount = sel $ "list" <> "balance" <> "negative"
|
||||||
| otherwise = sel $ "list" <> "balance" <> "positive"
|
| otherwise = sel $ "list" <> "balance" <> "positive"
|
||||||
sel | selected = (<> "selected")
|
sel | selected = (<> "selected")
|
||||||
| otherwise = id
|
| otherwise = id
|
||||||
|
|
||||||
handleRegisterScreen :: AppState -> Vty.Event -> EventM (Next AppState)
|
handleRegisterScreen :: AppState -> Vty.Event -> EventM (Next AppState)
|
||||||
handleRegisterScreen st@AppState{
|
handleRegisterScreen st@AppState{
|
||||||
aScreen=s@RegisterScreen{rsState=(l,acct)}
|
aScreen=s@RegisterScreen{rsState=rsState@RegisterScreenState{..}}
|
||||||
,aopts=UIOpts{cliopts_=copts}
|
,aopts=UIOpts{cliopts_=copts}
|
||||||
,ajournal=j
|
,ajournal=j
|
||||||
,aMinibuffer=mbuf
|
,aMinibuffer=mbuf
|
||||||
@ -242,20 +245,22 @@ handleRegisterScreen st@AppState{
|
|||||||
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
|
||||||
case listSelectedElement l of
|
case listSelectedElement rsItems of
|
||||||
Just (_, (_, _, _, _, _, t)) ->
|
Just (_, RegisterScreenItem{rsItemTransaction=t}) ->
|
||||||
let
|
let
|
||||||
ts = map sixth6 $ V.toList $ listElements l
|
ts = map rsItemTransaction $ V.toList $ listElements rsItems
|
||||||
numberedts = zip [1..] ts
|
numberedts = zip [1..] ts
|
||||||
i = fromIntegral $ maybe 0 (+1) $ elemIndex t ts -- XXX
|
i = fromIntegral $ maybe 0 (+1) $ elemIndex t ts -- XXX
|
||||||
in
|
in
|
||||||
continue $ screenEnter d transactionScreen{tsState=((i,t),numberedts,acct)} st
|
continue $ screenEnter d transactionScreen{tsState=TransactionScreenState{tsTransaction=(i,t)
|
||||||
|
,tsTransactions=numberedts
|
||||||
|
,tsSelectedAccount=rsSelectedAccount}} st
|
||||||
Nothing -> continue st
|
Nothing -> continue st
|
||||||
|
|
||||||
-- fall through to the list's event handler (handles [pg]up/down)
|
-- fall through to the list's event handler (handles [pg]up/down)
|
||||||
ev -> do
|
ev -> do
|
||||||
l' <- handleEvent ev l
|
newitems <- handleEvent ev rsItems
|
||||||
continue st{aScreen=s{rsState=(l',acct)}}
|
continue st{aScreen=s{rsState=rsState{rsItems=newitems}}}
|
||||||
-- continue =<< handleEventLensed st someLens ev
|
-- continue =<< handleEventLensed st someLens ev
|
||||||
|
|
||||||
Just ed ->
|
Just ed ->
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
-- The transaction screen, showing a single transaction's general journal entry.
|
-- The transaction screen, showing a single transaction's general journal entry.
|
||||||
|
|
||||||
{-# LANGUAGE OverloadedStrings, TupleSections #-} -- , FlexibleContexts
|
{-# LANGUAGE OverloadedStrings, TupleSections, RecordWildCards #-} -- , FlexibleContexts
|
||||||
|
|
||||||
module Hledger.UI.TransactionScreen
|
module Hledger.UI.TransactionScreen
|
||||||
(transactionScreen
|
(transactionScreen
|
||||||
@ -37,7 +37,9 @@ import Hledger.UI.ErrorScreen
|
|||||||
|
|
||||||
transactionScreen :: Screen
|
transactionScreen :: Screen
|
||||||
transactionScreen = TransactionScreen{
|
transactionScreen = TransactionScreen{
|
||||||
tsState = ((1,nulltransaction),[(1,nulltransaction)],"")
|
tsState = TransactionScreenState{tsTransaction=(1,nulltransaction)
|
||||||
|
,tsTransactions=[(1,nulltransaction)]
|
||||||
|
,tsSelectedAccount=""}
|
||||||
,sInitFn = initTransactionScreen
|
,sInitFn = initTransactionScreen
|
||||||
,sDrawFn = drawTransactionScreen
|
,sDrawFn = drawTransactionScreen
|
||||||
,sHandleFn = handleTransactionScreen
|
,sHandleFn = handleTransactionScreen
|
||||||
@ -45,15 +47,17 @@ transactionScreen = TransactionScreen{
|
|||||||
|
|
||||||
initTransactionScreen :: Day -> Bool -> AppState -> AppState
|
initTransactionScreen :: Day -> Bool -> AppState -> AppState
|
||||||
initTransactionScreen _d _reset st@AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=_ropts}}
|
initTransactionScreen _d _reset st@AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=_ropts}}
|
||||||
,ajournal=_j
|
,ajournal=_j
|
||||||
,aScreen=s@TransactionScreen{tsState=((n,t),nts,a)}} =
|
,aScreen=TransactionScreen{..}} = st
|
||||||
st{aScreen=s{tsState=((n,t),nts,a)}}
|
|
||||||
|
|
||||||
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=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
drawTransactionScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
||||||
,aScreen=TransactionScreen{tsState=((i,t),nts,acct)}} = [ui]
|
,aScreen=TransactionScreen{
|
||||||
|
tsState=TransactionScreenState{tsTransaction=(i,t)
|
||||||
|
,tsTransactions=nts
|
||||||
|
,tsSelectedAccount=acct}}} =
|
||||||
|
[ui]
|
||||||
where
|
where
|
||||||
-- datedesc = show (tdate t) ++ " " ++ tdescription t
|
-- datedesc = show (tdate t) ++ " " ++ tdescription t
|
||||||
toplabel =
|
toplabel =
|
||||||
@ -95,11 +99,14 @@ drawTransactionScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
|
|||||||
drawTransactionScreen _ = error "draw function called with wrong screen type, should not happen"
|
drawTransactionScreen _ = error "draw function called with wrong screen type, should not happen"
|
||||||
|
|
||||||
handleTransactionScreen :: AppState -> Vty.Event -> EventM (Next AppState)
|
handleTransactionScreen :: AppState -> Vty.Event -> EventM (Next AppState)
|
||||||
handleTransactionScreen st@AppState{
|
handleTransactionScreen
|
||||||
aScreen=s@TransactionScreen{tsState=((i,t),nts,acct)}
|
st@AppState{aScreen=s@TransactionScreen{tsState=tsState@TransactionScreenState{tsTransaction=(i,t)
|
||||||
,aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}
|
,tsTransactions=nts
|
||||||
,ajournal=j
|
,tsSelectedAccount=acct}}
|
||||||
} e = do
|
,aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}
|
||||||
|
,ajournal=j
|
||||||
|
}
|
||||||
|
e = do
|
||||||
d <- liftIO getCurrentDay
|
d <- liftIO getCurrentDay
|
||||||
let
|
let
|
||||||
(iprev,tprev) = maybe (i,t) ((i-1),) $ lookup (i-1) nts
|
(iprev,tprev) = maybe (i,t) ((i-1),) $ lookup (i-1) nts
|
||||||
@ -131,18 +138,20 @@ handleTransactionScreen st@AppState{
|
|||||||
Nothing | null numberedts -> (0,nulltransaction)
|
Nothing | null numberedts -> (0,nulltransaction)
|
||||||
| i > fst (last numberedts) -> last numberedts
|
| i > fst (last numberedts) -> last numberedts
|
||||||
| otherwise -> head numberedts
|
| otherwise -> head numberedts
|
||||||
st' = st{aScreen=s{tsState=((i',t'),numberedts,acct)}}
|
st' = st{aScreen=s{tsState=TransactionScreenState{tsTransaction=(i',t')
|
||||||
|
,tsTransactions=numberedts
|
||||||
|
,tsSelectedAccount=acct}}}
|
||||||
continue $ regenerateScreens j' d st'
|
continue $ regenerateScreens j' d st'
|
||||||
|
|
||||||
Left err -> continue $ screenEnter d errorScreen{esState=err} st
|
Left err -> continue $ screenEnter d errorScreen{esState=ErrorScreenState{esError=err}} st
|
||||||
|
|
||||||
-- if allowing toggling here, we should refresh the txn list from the parent register screen
|
-- if allowing toggling here, we should refresh the txn list from the parent register screen
|
||||||
-- Vty.EvKey (Vty.KChar 'E') [] -> continue $ regenerateScreens j d $ stToggleEmpty st
|
-- Vty.EvKey (Vty.KChar 'E') [] -> continue $ regenerateScreens j d $ stToggleEmpty st
|
||||||
-- Vty.EvKey (Vty.KChar 'C') [] -> continue $ regenerateScreens j d $ stToggleCleared st
|
-- Vty.EvKey (Vty.KChar 'C') [] -> continue $ regenerateScreens j d $ stToggleCleared st
|
||||||
-- Vty.EvKey (Vty.KChar 'R') [] -> continue $ regenerateScreens j d $ stToggleReal st
|
-- Vty.EvKey (Vty.KChar 'R') [] -> continue $ regenerateScreens j d $ stToggleReal st
|
||||||
|
|
||||||
Vty.EvKey (Vty.KUp) [] -> continue $ regenerateScreens j d st{aScreen=s{tsState=((iprev,tprev),nts,acct)}}
|
Vty.EvKey (Vty.KUp) [] -> continue $ regenerateScreens j d st{aScreen=s{tsState=tsState{tsTransaction=(iprev,tprev)}}}
|
||||||
Vty.EvKey (Vty.KDown) [] -> continue $ regenerateScreens j d st{aScreen=s{tsState=((inext,tnext),nts,acct)}}
|
Vty.EvKey (Vty.KDown) [] -> continue $ regenerateScreens j d st{aScreen=s{tsState=tsState{tsTransaction=(inext,tnext)}}}
|
||||||
|
|
||||||
Vty.EvKey (Vty.KLeft) [] -> continue st''
|
Vty.EvKey (Vty.KLeft) [] -> continue st''
|
||||||
where
|
where
|
||||||
@ -153,7 +162,7 @@ handleTransactionScreen st@AppState{
|
|||||||
|
|
||||||
handleTransactionScreen _ _ = error "event handler called with wrong screen type, should not happen"
|
handleTransactionScreen _ _ = error "event handler called with wrong screen type, should not happen"
|
||||||
|
|
||||||
rsSetSelectedTransaction i scr@RegisterScreen{rsState=(l,a)} = scr{rsState=(l',a)}
|
rsSetSelectedTransaction i scr@RegisterScreen{rsState=rsState@RegisterScreenState{..}} = scr{rsState=rsState{rsItems=l'}}
|
||||||
where l' = listMoveTo (i-1) l
|
where l' = listMoveTo (i-1) rsItems
|
||||||
rsSetSelectedTransaction _ scr = scr
|
rsSetSelectedTransaction _ scr = scr
|
||||||
|
|
||||||
|
|||||||
@ -62,51 +62,75 @@ data AppState = AppState {
|
|||||||
-- partial functions, so take care.
|
-- partial functions, so take care.
|
||||||
data Screen =
|
data Screen =
|
||||||
AccountsScreen {
|
AccountsScreen {
|
||||||
asState :: (List -- list widget holding:
|
asState :: AccountsScreenState
|
||||||
(Int -- indent level
|
,sInitFn :: Day -> Bool -> AppState -> AppState -- ^ function to generate the screen's state on entry or change
|
||||||
,AccountName -- full account name
|
,sDrawFn :: AppState -> [Widget] -- ^ brick renderer for this screen
|
||||||
,AccountName -- full or short account name to display
|
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) -- ^ brick event handler for this screen
|
||||||
,[String] -- rendered amounts
|
|
||||||
)
|
|
||||||
,AccountName -- full name of the currently selected account (or "")
|
|
||||||
)
|
|
||||||
,sInitFn :: Day -> Bool -> AppState -> AppState -- ^ function to generate/update the screen's state,
|
|
||||||
-- takes the current date and whether to reset the selection.
|
|
||||||
,sDrawFn :: AppState -> [Widget] -- ^ brick renderer to use for this screen
|
|
||||||
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) -- ^ brick event handler to use for this screen
|
|
||||||
}
|
}
|
||||||
| RegisterScreen {
|
| RegisterScreen {
|
||||||
rsState :: (List -- list widget holding:
|
rsState :: RegisterScreenState
|
||||||
(String -- date
|
|
||||||
,String -- description
|
|
||||||
,String -- other accts
|
|
||||||
,String -- change amt
|
|
||||||
,String -- balance amt
|
|
||||||
,Transaction -- the full transaction
|
|
||||||
)
|
|
||||||
,AccountName -- full name of the acct we are showing a register for
|
|
||||||
)
|
|
||||||
,sInitFn :: Day -> Bool -> AppState -> AppState
|
,sInitFn :: Day -> Bool -> AppState -> AppState
|
||||||
,sDrawFn :: AppState -> [Widget]
|
,sDrawFn :: AppState -> [Widget]
|
||||||
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState)
|
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState)
|
||||||
}
|
}
|
||||||
| TransactionScreen {
|
| TransactionScreen {
|
||||||
tsState :: ((Integer, Transaction) -- the (numbered) transaction we are currently viewing
|
tsState :: TransactionScreenState
|
||||||
,[(Integer, Transaction)] -- the list of numbered transactions we can step through
|
|
||||||
,AccountName -- the account whose register we entered this screen from
|
|
||||||
)
|
|
||||||
,sInitFn :: Day -> Bool -> AppState -> AppState
|
,sInitFn :: Day -> Bool -> AppState -> AppState
|
||||||
,sDrawFn :: AppState -> [Widget]
|
,sDrawFn :: AppState -> [Widget]
|
||||||
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState)
|
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState)
|
||||||
}
|
}
|
||||||
| ErrorScreen {
|
| ErrorScreen {
|
||||||
esState :: String -- error message to display
|
esState :: ErrorScreenState
|
||||||
,sInitFn :: Day -> Bool -> AppState -> AppState
|
,sInitFn :: Day -> Bool -> AppState -> AppState
|
||||||
,sDrawFn :: AppState -> [Widget]
|
,sDrawFn :: AppState -> [Widget]
|
||||||
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState)
|
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState)
|
||||||
}
|
}
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
|
-- | Render state for this type of screen.
|
||||||
|
data AccountsScreenState = AccountsScreenState {
|
||||||
|
asItems :: List AccountsScreenItem -- ^ list of account names & balances
|
||||||
|
,asSelectedAccount :: AccountName -- ^ full name of the currently selected account (or "")
|
||||||
|
} deriving (Show)
|
||||||
|
|
||||||
|
-- | An item in the accounts screen's list of accounts and balances.
|
||||||
|
data AccountsScreenItem = AccountsScreenItem {
|
||||||
|
asItemIndentLevel :: Int -- ^ indent level
|
||||||
|
,asItemAccountName :: AccountName -- ^ full account name
|
||||||
|
,asItemDisplayAccountName :: AccountName -- ^ full or short account name to display
|
||||||
|
,asItemRenderedAmounts :: [String] -- ^ rendered amounts
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Render state for this type of screen.
|
||||||
|
data RegisterScreenState = RegisterScreenState {
|
||||||
|
rsItems :: List RegisterScreenItem -- ^ list of transactions affecting this account
|
||||||
|
,rsSelectedAccount :: AccountName -- ^ full name of the account we are showing a register for
|
||||||
|
} deriving (Show)
|
||||||
|
|
||||||
|
-- | An item in the register screen's list of transactions in the current account.
|
||||||
|
data RegisterScreenItem = RegisterScreenItem {
|
||||||
|
rsItemDate :: String -- ^ date
|
||||||
|
,rsItemDescription :: String -- ^ description
|
||||||
|
,rsItemOtherAccounts :: String -- ^ other accounts
|
||||||
|
,rsItemChangeAmount :: String -- ^ the change to the current account from this transaction
|
||||||
|
,rsItemBalanceAmount :: String -- ^ the balance or running total after this transaction
|
||||||
|
,rsItemTransaction :: Transaction -- ^ the full transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
-- | Render state for this type of screen.
|
||||||
|
data TransactionScreenState = TransactionScreenState {
|
||||||
|
tsTransaction :: NumberedTransaction -- ^ the transaction we are currently viewing, and its position in the list
|
||||||
|
,tsTransactions :: [NumberedTransaction] -- ^ the list of transactions we can step through
|
||||||
|
,tsSelectedAccount :: AccountName -- ^ the account whose register we entered this screen from
|
||||||
|
} deriving (Show)
|
||||||
|
|
||||||
|
type NumberedTransaction = (Integer, Transaction)
|
||||||
|
|
||||||
|
-- | Render state for this type of screen.
|
||||||
|
data ErrorScreenState = ErrorScreenState {
|
||||||
|
esError :: String -- ^ error message to show
|
||||||
|
} deriving (Show)
|
||||||
|
|
||||||
instance Show (List a) where show _ = "<List>"
|
instance Show (List a) where show _ = "<List>"
|
||||||
instance Show Editor where show _ = "<Editor>"
|
instance Show Editor where show _ = "<Editor>"
|
||||||
|
|
||||||
|
|||||||
@ -133,10 +133,10 @@ regenerateScreens j d st@AppState{aScreen=s,aPrevScreens=ss} =
|
|||||||
-- remove all the screens from the appstate and then add them back
|
-- remove all the screens from the appstate and then add them back
|
||||||
-- one at a time, regenerating as we go.
|
-- one at a time, regenerating as we go.
|
||||||
let
|
let
|
||||||
first:rest = reverse $ s:ss
|
first:rest = reverse $ s:ss :: [Screen]
|
||||||
st0 = st{ajournal=j, aScreen=first, aPrevScreens=[]}
|
st0 = st{ajournal=j, aScreen=first, aPrevScreens=[]} :: AppState
|
||||||
st1 = (sInitFn first) d False st0
|
st1 = (sInitFn first) d False st0 :: AppState
|
||||||
st2 = foldl' (\st s -> (sInitFn s) d False $ pushScreen s st) st1 rest
|
st2 = foldl' (\st s -> (sInitFn s) d False $ pushScreen s st) st1 rest :: AppState
|
||||||
in
|
in
|
||||||
st2
|
st2
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user