-
Notifications
You must be signed in to change notification settings - Fork 10
Configuring new Flutter constructors for f mx
Matrix code has always involved simple trees of models. This in turn makes coding simpler, with nesting alone expressing trees. HTML and many UI libraries work the same.
Not Flutter. As a full-blown OO library, it simply produced different structures for different widgets, where HTML adopted all-children-all-the-time. Furthermore, with Dart a strongly typed language, it was not an option to use :children for widgets with only one child. :children expects a collection.
As I cooked up the Flutter/MX wrappers for Flutter widgets, I did what I could to recreate the HTML consistency.
-
First, find the Flutter constructor in the reference. For example, googling "flutter scaffold" offered many hits, but I grabbed the one advertising the Scaffold class - material library - Flutter - Dart API docs.
-
Next, is it stateful? Not always easy to determine! When in doubt, I look for a section called "Inheritance". Here is the entry for Scaffold:
Inheritance
Object > DiagnosticableTree > Widget > StatefulWidget (bingo!) > Scaffold
- Next, does it take :child or :children?
Scaffold does not.
- Next, is there some attribute that would be a child in HTML, such as the content of a text widget?
Scaffold takes a body
, a great candidate for a nested child. So:
(deftag tiltontec.flutter-mx.factory/k1-body-stateful scaffold m/Scaffold)
...which says we can code scaffolds as if they have one child, and the f/mx
logic will pass that along to Flutter as :body
.
(fx/scaffold
{:appBar (fx/app-bar
{:title (m/Text "Flutter/MX Counter")})
:floatingActionButton (cF (fx/floating-action-button
{:onPressed (as-dart-callback []
(mswap! (fm* :z-counter) :value inc))
:tooltip "Increment"}
(m/Icon m.Icons/add)))}
(fx/center
(fx/column {:mainAxisAlignment m.MainAxisAlignment/center}
(fx/text "You have pushed (+) this many times:")
(fx/text {:style (fx/in-my-context [me ctx]
(.-headline4 (.-textTheme (m.Theme/of ctx))))}
{:name :z-counter
:value (cI 0)}
(str (md/my-value))))))
That is just one example of how the answers to these questions guide my choice of existing wrappers, and may even force the creation of new wrappers. Ping me any time you need any help here, ideally with an existing Dart/Flutter or CLJD/Flutter example to replicate.
Now let us work thru some more examples to discover the edge cases I have handled so far.
- k1-child-stateful: only one child is allowed, and that will be passed as
:child
to the constructor. - k1-child-stateless: see stateful variant
- k1-content-stateless: only one child is allowed, and that will be passed as
:content
to the constructor. - children-stateless: the MX
kids
get passed as:children
. - childless-stateless: simple. Examples: AppBar, DataTable, RoundedRectangleBorder, ListTile, FlutterLogo
- konly-param1-stateless: only one child allowed, and that is passed as the first parameter to the constructor. Example: Text.
- konly-param1-stateful: same as stateless ^^ variant, but stateful. Only example is the
f/mx
text!
widget. See "Exceptions" below. - childless-stateful: nice, terminal widgets. Examples: CheckBox, TextField.
- prop-param1-childless-stateful: same as childless-stateful, with a twist. Consider Flutter
m/Icon
. It wants the icon as the first parameter to the constructor. In CLJD-ese:
(m/Icon m.Icons/add .color m.Colors/black)
But f/mx
works by building proxy objects, not by providing new constructors. So we need to provide "parameter one" as a property, and let f/mx
take care of calling the Flutter constructor appropriately:
(fx/icon {:icon m.Icons/add :color m.Colors/black})
- k1-home-stateful: The Flutter widget takes a
:home
property that works better as the only child. Example: material-app. - prop-param1-childless-stateless: unused. Vestigial?
Here is one interesting exception, anyway.
Flutter has the Text widget as stateless. Matrix GUIs do quite a lot with reactive text. An example from f/mx
TodoMVC:
(defn to-do-display [todo]
(fx/list-tile
{:leading (completion-toggler todo)
:trailing (delete-button todo)
:title (cF (let [comp-toggle (md/mget me :leading)]
(fx/text!
{:style (cF (if (md/mget comp-toggle :value)
(p/TextStyle
.color m.Colors/grey
.decoration p.TextDecoration/lineThrough)
(p/TextStyle .color
(if (mget todo :ae-events?)
m.Colors/red
m.Colors/blue))))}
(td-title todo))))}
{:name :my-list-tile
:todo todo}))
If I use a stateless option:
(deftagleaf tiltontec.flutter-mx.factory/konly-param1-stateless text m/Text)
The Todo item does not get highlighted until something else triggers a larger scope redraw. So we keep that as presumably more light weight, then add a second definition involving state:
(deftagleaf tiltontec.flutter-mx.factory/konly-param1-stateful text! m/Text)
FYI, the expansion of that reifies m/StatefulWidget
, while the build function invokes the m/Text
constructor. This lets f/mx
dispatch a precision targeted .setState
, rather than do so excessively just to get one text widget redrawn. No idea if there was a better way.
.