Time Cop
Back in February 2020, I decided to write my own time-tracking app. Time Cop is the result.
I hate time-tracking, but it is a requirement of my job (grants that help pay for my job, really) and if I don’t have an app handy, I tend to forget to record my time. I’ve tried numerous time-tracking apps on the app stores, but they’ve each fallen short for me in some way or another—many are too complicated, or don’t just work, or cost more than I think is reasonable. Many necessitate sending data over the network for multi-device sync—a feature I have no need of, but can never disable.
Since time tracking is fairly simple, I decided to write my own app to scratch my own itch, in the spirit of “An app can be a home-cooked meal”. I also decided to publish the app and use it as a learning experience—I’ve worked on parts of mobile apps before, and developed proof-of-concept mobile apps before, but I wanted to follow the process through from start to end. I also decided to localize it (using Google Translate) for the experience of doing so. My biggest take away from all of this is that the work required to create and manage a store presence (localization and especially localized screenshots) is almost an order of magnitude more work than programming the damned thing in the first place.
I only had vague requirements in mind, roughly along the lines of:
- Offline-only
- No backend / server to write or maintain
- Target iOS (my phone)
- I always have it with me, unlike an internet website
- Might as well target Android too since I didn’t know a lick about iOS programming
- Use Flutter (path of least resistance for me on mobile)
- Track multiple items in parallel
- Sometimes things just overlap, don’t be too prescriptive about it all
- Easy export to spreadsheets
- My company tracks all time in spreadsheets 🤷
- Most importantly: completely private
- I’m tired of having my data sold to the highest bidder, or used against me in unforeseen ways
- Immeasurably more simple
With these things in mind, I started hacking away. I had already played with Flutter to great success and even implemented a (cancelled) project in it at my company the year before, so it was pretty easy to get going. I actually got the initial prototype up and running much more quickly than I had hoped. I think I can attribute this to the amazing hot-reload in Flutter combined with defining the entire UI in code—no farting around with some UI designer, just change a line here, Ctrl+S, and instantly see the changes with live data. This felt like (and really, still feels like a superpower when programming—so much so that I’ve started to implement hot-reload capabilities as much as I can whenever I do UI work at work. My initial goal was to stop using Clockify and start using my own app for recording my time as soon as possible. I went from a blank repository to a minimal prototype that did this in about 2 or 3 days, and I think I can credit the continued development of the app to the fact I was able to get a working MVP out and dog-food it so quickly—this let me comfortably explore new features as I felt like them, rather than feeling pressured to build a core product. Granted, this is infinitely easier if you keep the scope of the app small to begin with; time-tracking is done easily enough with a pen and paper and so the business logic should be just as straightforward.
In general I’m a big fan of the “reactive ui” paradigm, where the state of your UI is naturally derived from the underling state of the app. A quick search lead me to the BloC Architecture which lead me to the bloc library. The approach was different than what I had done before, but it seemed straightforward enough so I went about building the app around this library and approach. In hindsight I don’t know if this was an ideal approach for me or not—in some ways it helped organize the app and keep development speed up, but I also found myself tripping over the semantics and nitty-gritty much more so than I am used to. Since I started development on Time Cop, the flutter_bloc
has had two major releases which may have fixed these pain points, but I’m too scared to investigate upgrading as doing so would likely change almost the entirety of the app and that’s just not worth it for me.