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. Table checks its keybinds before its own navigation, so an enter bind would take the key away from the widget permanently โ€” including in the frames before the mode exists. The mode test lives inside the on-activate tap 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 the sidebar hint context and the register under register; the sidebar is the tab's initial focus, and Enter on it moves focus to the register.

  • install-subscriptions() / install-keybinds() โ€” the two seams Screen::Main::Subscriptions::install-content and Screen::Main::Keybinds::install-content call.

  • 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

  • the sidebar, which also watches the closed-bucket fold;

  • the register, which also watches the selected account.

App::Moneymoor v0.4.2

YNAB-style envelope budgeting: a derivation engine

Authors

  • Matt Doughty

License

Artistic-2.0

Dependencies

DBIish:ver<0.6.7>:auth<zef:raku-community-modules>Notcurses::Native:ver<0.6.5+>:auth<zef:apogee>Selkie:ver<0.16.0+>:auth<zef:apogee>JSON::Fast:ver<0.19>:auth<cpan:TIMOTIMO>MacOS::NativeLib:ver<0.0.6>:auth<zef:lizmat>

Test Dependencies

Provides

  • App::Moneymoor
  • App::Moneymoor::Config
  • App::Moneymoor::DB
  • App::Moneymoor::Gateway::Account
  • App::Moneymoor::Gateway::Assignment
  • App::Moneymoor::Gateway::Category
  • App::Moneymoor::Gateway::Payee
  • App::Moneymoor::Gateway::Transaction
  • App::Moneymoor::Handlers::Boot
  • App::Moneymoor::Model::Account
  • App::Moneymoor::Model::Assignment
  • App::Moneymoor::Model::Category
  • App::Moneymoor::Model::CategoryGroup
  • App::Moneymoor::Model::Payee
  • App::Moneymoor::Model::Split
  • App::Moneymoor::Model::Transaction
  • App::Moneymoor::Screen::Accounts
  • App::Moneymoor::Screen::Budget
  • App::Moneymoor::Screen::Login
  • App::Moneymoor::Screen::Main
  • App::Moneymoor::Screen::Main::Keybinds
  • App::Moneymoor::Screen::Main::Modals
  • App::Moneymoor::Screen::Main::Subscriptions
  • App::Moneymoor::Screen::Reports
  • App::Moneymoor::Service::Budget
  • App::Moneymoor::Service::Icons
  • App::Moneymoor::Service::Target
  • App::Moneymoor::Service::Workspace
  • App::Moneymoor::StoreHandlers
  • App::Moneymoor::Theme
  • App::Moneymoor::Theme::Catppuccin
  • App::Moneymoor::Theme::Dracula
  • App::Moneymoor::Theme::Everforest
  • App::Moneymoor::Theme::Gruvbox
  • App::Moneymoor::Theme::Kanagawa
  • App::Moneymoor::Theme::Monokai
  • App::Moneymoor::Theme::Nord
  • App::Moneymoor::Theme::OneDark
  • App::Moneymoor::Theme::RosePine
  • App::Moneymoor::Theme::Solarized
  • App::Moneymoor::Theme::TokyoNight
  • App::Moneymoor::Themes
  • App::Moneymoor::UI
  • App::Moneymoor::Util::Money
  • App::Moneymoor::Util::Period
  • App::Moneymoor::View::BudgetRow
  • App::Moneymoor::View::EmptyState
  • App::Moneymoor::View::HintBar
  • App::Moneymoor::View::InspectorPane
  • App::Moneymoor::View::ModalChrome
  • App::Moneymoor::View::RegisterRow
  • App::Moneymoor::View::ReportRow
  • App::Moneymoor::Widget::BannerBar
  • App::Moneymoor::Widget::BootProgressModal

The Camelia image is copyright 2009 by Larry Wall. "Raku" is a trademark of the Yet Another Society. All rights reserved.

Built with Podlite โ€” the markup and publishing tools behind this site.