Last update: 2024-07-22
There has been an Android/iOS/PWA-sized hole in me for some time, and I decided to fill that this summer with Google's Flutter framework, to make an app for my old iPhone and replace my dead clock radio. Another option would've been React Native and Typescript, but having less legacy baggage seems best when learning a new paradigm. I'm still likely to dig into RN later since it is the more popular framework. Flutter has very much the same position in Dart ecosystem, as Rails do on Ruby.
Dart
Originally designed as a successor to Javascript, Dart's syntax surprised me with how straightforward it was to learn. C-like with static typing, and close to C++ with its OO paradigm. So, a verbose language from a Haskell perspective, but does what it's told and as modern language with modern tooling pleasantly guiderails me away from footguns.
One of the guiderails I've really liked is leaning on immutability with its distinction between final
and const
. Where as const
is a traditional compile-time constant variable, final
is variable that stays constant after its initial runtime assignment. To extend usability of final
, it can be prefixed with late
as promise by the programmer to have it initialized before actually using it. Interestingly though, final
does not mean much with classes. A class assigned to a final
is still mutable. To mitigate this, you can use @immutable
compiler macro to add some heuristics to see if a class is mutable or not.
The way Dart does optional types feels tacked on, revolving around null
, but still, does what it is expected to do. The important thing is that all types lack null
by default. With null-aware operators and ?
notation handling null
-able types explicitly is nice and fluid.
When initializing classes, Dart interestingly denies doing any function calls in default constructors. Only factory
methods can be used for more involved class initialization. Multiple inheritance is also missing, with mixins filling in the role.
Flutter
Flutter (and Dart) has a pronouncedly batteries-included vibe; the standard library is extensive and seems to cover the bases any mainstream app would require. Its association with Google though is clear: you have to run through hoops to avoid a Flutter PWA from accessing Gstatic for both the default fonts and CanvasKit. And to my experience, using local rather than CDN CanvasKit files is patchy. If I change the web renderer from auto
to canvaskit
, it suddenly starts fetching Canvaskit from Google CDN even with FLUTTER_WEB_CANVASKIT_URL
set to local file.
Nevertheless for its arrogant vibe expected from FAANG corps, Flutter is a breeze to develop with and works mostly as expected on all 6 platforms (Win/Linux/MacOS/Android/iOS/PWA). Flutter is a "MVC+S" framework (S being Service), which on par with distributed architectures being the default. Probably makes GCP marketing team happy too.
Interestingly the skeleton template in Flutter divides the source code into folders named after features. I haven't written big enough projects that I would've run into the debate between features and types in project folder structuring, but apparently it's a thing. I do agree it's a good idea to use features as the naming scheme.
Clock radio app
I wanted to write an exploratory prototype for a clock radio app that
- Shows time on a clock face 24/7 beside my bed, without disturbing my sleep.
- Can play internet radio channels and playing the radio works as an alarm
First I wanted to replicate the LED screen from my old clock radio. I didn't want to trace the screen, so I just drew an artesanal SVG off it.
All 30 elements were put into their own <1kB SVG files, so when the app inteprets current time into ABCDEFG 7-segment led, it looks like this in-app (I did rework the alarm into a bell). The clock face can be tapped to turn radio on and off
With a long press, I could then move to settings tab, and set my alarm time in my barebones-only-I-understand-what-everything-does settings tab.
For all intents and purposes, the clock radio was now ready.
A feature idea
During development, I woke up with an idea about a solar clock face. My pet peevee about timekeeping has been that solar noon happens around 13.30 during DST. I wanted to do a timezone-less clock face that centered around the solar noon in a given longitude, and also could derive sunrise and sunset from latitude. I sketched this.
Playing around with some trigonometry and Flutter's extensive CustomPaint
I could then finally draw this clock face for those days when I don't have to live by an exact schedule. The outline-only sun is for when the alarm is set. In this case, 7.30, so 6 hours or 90° before solar noon. Yellow dot is where I live. I had to tone down the dayside to a gray, since otherwise it would light up my room to much.
In action
CADding and printing a stand, I now have a functional clock radio that wakes me up every day. Now I can bring it to my work desk for the day: it can do about 24 hours without charging. Unlike my old clock radio.