_blogs
// blogs / 20260815.md
// blogs / 20260815.md
Dev Log: August 15 Wrap-up
Overview
Today was one of those days where I bounced between big-picture features and those tiny, annoying UI bugs that you can't help but fix once you notice them. The highlight was finally getting a solid Backup & Restore system working without bloating the app with extra dependencies.
What I Worked On
Building a lightweight Backup & Restore
I’ve been meaning to add a way to export and import data for a while. Instead of pulling in a massive serialization library, I decided to stick with the standard org.json that comes with Android. The schema for this app is flat enough that hand-rolling the encoder and decoder was actually faster than setting up a full-blown library configuration.
One thing that tripped me up was the UX of importing. If a user imports data from six months ago while they’re looking at the current month’s dashboard, it looks like nothing happened. I ended up adding a timestamp return to the import logic so the app can automatically jump the view to the month where the new data actually lives. It’s a small touch, but it prevents that "Wait, did it work?" moment of confusion.
Refining the transaction matching
During the import process, I had to refine how we detect duplicate transactions. It’s not enough to just check the amount; you have to look at the payee too. But sometimes the payee names are just slightly different enough to fail a string match. I wrote a little helper to handle the logic for when payees actually "disagree":
/**
* Simple check to see if two transactions are actually different
* based on the reported names/entities.
*/
fun entries_conflict(parsed_name: String?, existing_name: String?): Boolean {
if (parsed_name.isNullOrBlank() || existing_name.isNullOrBlank()) {
return false // Not enough info to say they conflict
}
return !parsed_name.equals(existing_name, ignoreCase = true)
}
UI Polish: Chips and Navigation
I also spent some time fixing the "Add Transaction" screen. I noticed that if you typed a new category name but didn't "save" it yet, the UI didn't give you any feedback that it was selected. I fixed the chip logic so that a pending new category shows up visually just like the existing ones.
Also, navigation was losing the active filters when drilling down into category details. I updated the route arguments to pass the filter state along. It's much more seamless now—you don't feel like you're starting your search over every time you click a button.
It’s got a face now!
Finally, I stopped using the default Android robot icon. I put together a simple logo and updated the launcher background. It’s a small thing, but seeing a real icon on my home screen makes the project feel significantly more "real."
Wrapping Up
Persistence is solid, navigation is smarter, and the app looks better. Tomorrow, I think I’ll look into some edge cases in the SMS parsing logic—there are always a few weird bank formats that manage to break things. Catch you later.