Accounts
NAME
App::Moneymoor::Screen::Accounts - the accounts tab: the sidebar of ledgers and the register of the one that is selected.
SYNOPSIS
use App::Moneymoor::Screen::Accounts;
# Built by Screen::Main's content-host seam, never directly:
my $tab = App::Moneymoor::Screen::Accounts.new(main => $main);
$tab.build($content-host); # mounts the sidebar and the register
$tab.install-subscriptions; # store โ sidebar / register / titles
$tab.install-keybinds; # n e d c t on the register, n e c on the list
# What the modals in Screen::Main::Modals read back:
$tab.selected-transaction; # the Model::Transaction under the cursor
$tab.selected-account-id; # the sidebar's account, 0 = All Accounts
$tab.sidebar-row; # the sidebar row hash under the cursor
DESCRIPTION
HBox (the content host's child)
โ Border(fixed 26, 'Accounts', bottom 'net ยฃ12,400.00') โ ListView
โ Border(flex, 'Current ยท cleared ยฃ900 ยท working ยฃ850') โ Table
The two panes are one screen with one selection between them: the
sidebar decides which ledger the register shows, and it does it through
the store (accounts/selected-account-id) rather than by calling the
register directly, so a selection made with the arrow keys and one
restored after a rebuild travel the same path.
Everything painted here comes out of View::RegisterRow; this file is
the wiring.
The sidebar's captions are not selections
BUDGET and TRACKING are rows in the same ListView as the
accounts โ the widget has no notion of a section โ and the cursor can
land on one. ยง4.4 says a caption re-selects the previous account; this
does slightly better and steps in the direction of travel, because
bouncing straight back would make a caption a wall the user could never
arrow past.
The CLOSED (n) fold and All Accounts are selectable: one is a
toggle, the other is a real (if synthetic) ledger.
The cursor is restored by id, twice
Neither list has stable indices. The sidebar's rows move when an
account is created, closed or reordered; the register's move when a
transaction changes date. So the sidebar's cursor is restored by
account id and the register's by transaction id after every rebuild โ
and because ListView.set-items and Table.set-rows both fire
on-select, both restores happen behind a suppression flag with one
deliberate announcement at the end. Without it a rebuild would announce
whatever row happened to be under the old index, the register would
repaint for an account the user never chose, and โ the rebuild being
triggered by a selection-keyed subscription โ it would do it again
every tick.
Three change tokens, and why this tab uses the blunt one
The budget grid watches budget/digest and budget/catalogue.
Neither can see a payee's name, a memo or a cleared state, so a memo
edit or a c keypress would leave both byte-identical and repaint
nothing. The register and the sidebar key on ws/rev instead โ the
counter every recompute bumps โ which says "something was written"
without saying what. That is the right resolution for a pane that
rebuilds its rows wholesale anyway.
Reconcile mode lives in the frame
ยง4.5's mode changes three things and none of them is a row.
accounts/reconcile holds the account and the statement balance;
while it names the ledger on screen the frame's title becomes
'Reconciling ยท cleared ยฃA ยท statement ยฃS ยท diff ยฃD', the frame
itself takes the diff's colour (red until it is zero, green when it
lands โ a Border title has no style of its own, so the whole frame
is the signal), and the hint footer switches to the reconcile
context.
The two keys the mode takes over are taken over in the two different ways the widget allows:
Enter is not bound.
Tablechecks its keybinds before its own navigation, so anenterbind would take the key away from the widget permanently โ including in the frames before the mode exists. The mode test lives inside theon-activatetap instead, which is where Enter already arrives.Esc is bound, and is a no-op outside the mode. A keybind consumes the key outright, which is the point: Esc must not fall through while a reconciliation is running. It cannot get in a modal's way, because an open modal holds focus and the register never sees the key.
Switching ledger or tab ends the mode โ the store handlers do it, so there is one rule and not one per entry point โ and the cleared marks made in it stay. They are facts about transactions; only the mode is cancelled.
The balance column comes and goes
The running-balance column only exists in the single-account view, and
only when the terminal is at least BALANCE-MIN-COLS wide. Crossing
that threshold rebuilds the Table's columns โ Table has no
per-column visibility, so the column set is the only lever.
The width is read at every repaint rather than cached at build time:
the tab is built while the terminal size is already known, but a
terminal that is resized while another tab is mounted would otherwise
build the wrong columns. Screen::Main owns the one App.on-resize
callback in the app (resize callbacks accumulate with no way to remove
them, so a per-tab registration would leak one on every tab switch) and
calls handle-resize here.
METHODS
build($host)โ construct and mount. Registers the sidebar under thesidebarhint context and the register underregister; the sidebar is the tab's initial focus, and Enter on it moves focus to the register.install-subscriptions()/install-keybinds()โ the two seamsScreen::Main::Subscriptions::install-contentandScreen::Main::Keybinds::install-contentcall.refresh-sidebar()/refresh-register()โ the subscription callbacks, public because a modal that has just mutated something can ask for a repaint.handle-resize(Int $cols)โ the balance-column threshold.table,sidebar,sidebar-row,selected-account-id,selected-transaction,selected-transaction-id.reconcile-state/reconcilingโ ยง4.5's mode, for the ledger currently on screen.
SEE ALSO
App::Moneymoor::View::RegisterRow โ the rows, the columns, ยง2.
App::Moneymoor::Screen::Main::Modals โ what the keys open.
App::Moneymoor::StoreHandlers โ
accounts/select-account,accounts/toggle-closedandws/rev.
the sidebar, which also watches the closed-bucket fold;
the register, which also watches the selected account.