Published 2026-10-11 · 3 min read

Desktop widgets: record straight from the home screen

The entry point for recording a transaction was buried at the bottom of the account detail page. I turned it into an Android home screen widget: one tap opens that account's record sheet, with buttons to switch accounts and a waterline tied to the account's budget.

阅读中文版

The entry point for recording a transaction has always been buried at the bottom of the account detail page. To log a coffee, I had to unlock, open the app, find the account, tap Trade, and only then fill in the amount. Everyday logging is a small, frequent action, and a long path makes me skip it. On 11 October I built a home screen widget for myself: a record button sitting right on the home screen, one tap opening that account's record sheet.

It reuses the design already in the app, so there is no second UI to maintain. Flutter draws the widget's look into an image, and the widget on the home screen just stretches that image across the cell and takes the taps.

What I wanted from it

  • One tap to record. Tapping the body of the widget launches the app straight into that account's record panel, expense by default, switchable inside. Home screen to record is now a single step, with no need to find the account and then hit Trade.
  • A button to switch accounts, plus a switch to turn it off. When several widgets sit on the same screen, each one is pinned to its own account and they do not interfere. The widget has left and right buttons to move between accounts. If I want one widget to stay on a single account, I can turn the switch buttons off in settings, and the left/right hot zones disappear with them so there is nothing to hit by accident.
  • Tied to the account's budget. If the account has a budget for this month, the widget draws the remaining allowance as a waterline: how much is left, that is how high the card background fills from the bottom, with a wave on the surface. When the allowance runs out, the card stops filling. This effect has its own switch too.

The tap has to actually open the sheet

This is where the whole thing was easiest to break, and I broke it twice.

First, the hot zone got eaten. I originally put the tap on the root container of the whole card, and on some devices a child view claimed that region first, so tapping the widget did nothing at all. Moving the tap onto a container that fills the entire cell made both the body tap and the switch buttons reliable.

Second, the tap path was longer than I assumed. One tap passes through the native hot zone, a deep link, the app's own validation, and a relay page before it reaches the record sheet. If any link in that chain does not line up, the result the user sees is always the same: nothing happens. So there was no trick to it, only walking the chain link by link to confirm a tap really opens the sheet, testing cold start and warm start separately.

The image has to match the cell

The widget image is drawn ahead of time by Flutter, and the cell on the home screen just stretches it to fill. The catch is that the cell is never the size drawn in the design file. It looks fine on a phone, but on a tablet or an unfolded foldable the cell grows, the image stretches with it, and the text goes soft.

The fix is to let Flutter draw at the cell's real size. That size is not mine to pick, it comes from the system, and there is one set for portrait and another for landscape. Grab the wrong set and the moment the screen rotates you get an absurd ratio. When the system hands out no size at all, it falls back to the two defaults, 4×2 and 2×2.

Takeaways

  • The point of this feature was simple: give recording the shortest possible entry. Tap the widget on the home screen, land in the record sheet.
  • The tap path is longer than it looks, and if any link is off, the user just sees nothing happen, so it has to be verified link by link.
  • The widget shares one look with the app, and the price is that its size must come from the real cell, never from the design file.
← PreviousTwo AI desks: one archives, one actsNext →Redeem codes, and the background service I deleted on purpose

Back to devlog · Back to PFEx