Flutter Clutter is hard to read! Gonna clean it up! You know what I don’t like about ? Very little. However, I did have to get use to reading the long vertical lists of parameters. Most times, they weren’t just parameters, they’re a list of anonymous functions being passed as parameters which made it that much harder to read. And Man! At times, there is a lot of clutter! A lot of Flutter Clutter! Flutter Other Stories by Greg Perry Of course, one can adapt. It does has its merits, but I decided to clean it up a bit. Below is a ‘before and after’ picture. What do you think? Original vs. New ContactDetailsPage ContactDetailsPage By Example I’m using the repo., , as an example. I arbitrarily picked it. I’m not picking on those particular developers or anything. As it happens, it itself demonstrates the use of the , but my version is not some much about the ‘plugin’ but more about the ‘look and feel’. More about organization really. More about the MVC design pattern specifically. contacts_service contacts_service plugin So, do you like it? What do you see? I see clean. I can readily see the ‘data’ is coming from static references in a class called, Contacts. It’s coming from the Contact class’ ‘edit reference’ specifically. This is the app’s edit screen after all, and so we can see that the class, Contact, is in edit mode! Below is a closer look. You can see, for example, the property below is getting its data from Contact’s reference. You know that the AppBar’s title property accepts a Widget, and so you’ll guess correctly that the item ‘Contacts.edit.displayName.text’ therefore returns a Text Widget. Clean. AppBar.title displayName ContactDetailsPage.dart MVC is in play Of all my , the most popular has been so far. It talks about implementing the MVC design pattern in Flutter, and you’ll quickly see that MVC is in play here as well. Let’s look at the Contacts class. articles Flutter + MVC at Last! Contacts.dart If you’re familiar with my MVC implementation in Flutter, you’ll realize that the class, Contacts, is a Controller in the MVC design as it extends the class, ControllerMVC. You can also see it implements a static factory: Item 1 in Joshua Bloch’s now renowned 2001 original publication, . You see it imports the class, ContactsService — the Model part of this app. Effective Java Finally, you may have guessed that possibly everything referenced in this class is static (in keeping with of Joshua Bloch’s Effective Java 2nd ed.), and again, you’d be right. Item 22 Contacts.dart MVC Inside and Out Even the directory structure of the app reflects the MVC approach taken when this app was developed. Following a design pattern (any design pattern) provides a guideline, a structure, on how you organize your logic, how you organize your code — even how you organize your files and folders. Remaining consistent and studious to that structure, for example, allows a ‘turn over’ of developers to ‘hit the ground running’ when going from one project to another. For example, at a glance, they can see below where and what makes up ‘the View’, ‘the Controller’, and ‘the Model’ for this particular project. I’ve taken the and organized it in this chosen fashion. I suspect a developer not even familiar with MVC could come to understand ‘where everything lives’ in a reasonably short time. Good design patterns allow for that. original repo. A follow-up article detailing this directory structure is on my ‘to do’ list. This project’s directory structure and its contents Get it? Got it. Good! Now, go back up and look at that in the class, Contacts. It’s called, edit, and it references a ‘library private’ variable that, in turn, references the instantiated class, . Remember that ? You’ve see it before. It’s Contact in edit mode! There’s two more classes: and . See where I’m going with this? last getter ContactEdit getter ContactList ContactAdd You may have guessed there’s three things here; three ‘modes’ to this app. If you’ve guessed there’s three screens in this app: One for adding Contacts, one for editing Contacts and one for listing Contacts. Again, you’d be right. One From Another Let’s start from the end. Let’s look at the class, . Note, however, you’ll discover it extends from the class, . We’ll then look at that class which, as it happens, extends the class, . We’ll then look at that, which extends yet another class called . We’ll get to them all soon enough, but first, the class that helps ‘add’ a Contact in the app. ContactAdd ContactEdit ContactList ContactFields Class ContactAdd It Adds Up. Looking at the class above, you see that indeed this class, , extends the class, . You can see it’s not a very big class but does a lot of interesting things. Firstly, it optionally takes in an ‘Contact’ object in its first method called . It then assigns values to two properties called phone and email. Since they’re not defined here in this class, we can assume they‘re defined in it’s parent class or in another inherited class up the hierarchy. You can see that the method calls its parent’s method passing in that Contact object…if any. ContactAdd ContactEdit init() init() init() There’s a ‘library private’ variable assigned a class called PostalAddress. There’s a being provided by a called formKey, and there’s a method called onPressed. GlobalKey getter Now there’s some details I’ve missed, but what I really want you to look at now is how this class is then utilized in the ‘Add Contact’ screen for this app. Look for the ‘Contacts.add’ in all the code below. I’ll wait here. (There’s little red arrows below to help you out. It’s not a test after all.) See how the properties and methods found in the class, , will now make sense when you see when are where they’re applied below. getter ContactAdd AddContactPage.dart It Does Add Up! The ‘Add Contact’ screen needs a ‘form key’ for its form. Well, where does it get that form key from? Take a look back at the , and you’ll readily see where that form key is to come from. Clean. ContactAdd class When the FlatButton widget’s method is called (when a user presses the screen’s ‘save’ button) what method are you to call? Again, looking back at the , I’d say you’re to call its very own ‘onPressed’ method. This approach has a ‘bigger purpose.’ You can see the function actually dictates the api to be used by the Controller, no? onPressed ContactAdd class build() Another article detailing this is also on my ‘to do’ list. That list is getting long. Look at the data to be displayed when adding a new Contact. Can you readily guess what data is to be entered? Bet you can! (Hint: givenName, middleName, familyName, etc.) You can also readily see that the data is to be entered in a list of widgets as well. Let’s look at the below. See how the ‘data’ and ‘interface’ are not separated as much? TextFormField original screen AddContactPage.dart Now, scroll down and look at my version again. AddContactPage.dart What do you think? Edit A Contact What have we got next? Next, we’ve got editing a Contact. We can readily see that the class, , extends the class . What does one usually do with a Contact in a Contact list? We usually add, edit and delete a Contact, don’t we. We may even ‘undelete’ a Contact if we change our minds. Look below. What do you see? ContactEdit ContactList Class ContactEdit You can see the class, , calls static methods from the class, ContactService, (the Modal aspect of the app) to add a contact, to delete a contact, and to ‘undelete’ a contact. You can see that the contact object passed to these methods is first changed into a ‘map’ object. You also see the contact object parameter is optional, and if null, assigns the ‘library private’ variable, _contact. Note, that variable is from the parent class, . ContactEdit ContactList Contact! The Contact class has the , . As you see below, it also has a named constructor called Contact.fromMap. You can guess what that does. You don’t see them here, but that constructor assigns the map entries to a list of named after the Contact’s field names. However, you do see the list of ‘library private’ variables being assigned by those . Finally, you see the , toMap, that converts the Contact’s properties back into a Map. You’ll guess correctly that the ‘backend’ deals directly with Map objects. Clean. getter toMap setters setters getter Contact.dart List them Contacts The next class is the parent class of the previous two. It has a lone method called . You can see a mess of ‘library private’ variables being assigned a variety of ‘Field’ classes. All those variables are obviously defined from the parent class, . A ‘new’ Contact object is created if no Contact object is passed to the method. Note, the object is assigned to that variable, _contact, we saw in the previous class, . init() ContactFields init() ContactEdit Class ContactList What’s Your Field? Let’s take a quick peek at one of those ‘Field’ classes. The first one listed above is the class, DisplayName. This one is very much like the others, but like the others, it has to be specific and provide its particular field name, displayName. Note, the variable, value, is from the parent class, Field. Class DisplayName Note, is called when you save a Contact, for example, in the under the method, . While the circleAvatar is, of course, found in the main screen, . onSave() AddContactPage _formKey.currentState.save() ContactListPage A Field of Contacts The first class in this hierarchy is the last class we’ll look at, . You have seen how each class ‘builds upon the previous one’ in one degree or another. Now what does this class provide? It provides the the ‘field’ variables of the type, Field, along with their associated and . See below. ContactFields getters setters Class ContactFields List Your Contacts Below is the build function for the first or ‘main’ screen of this app. Those familiar with my implementation of , know I consider the function of the Widget for the ‘main’ screen of an app (the function of any Widget actually) to be ‘the View’ in the MVC implementation. Remember? MVC in Flutter build() build() For this app, any data displayed in ‘the View’ is accessed through the Controller. So in this case, Contacts is the controller for this app. Below, anywhere you see the word ‘contacts’, you know its value(s) are being drawn out of the Controller. You can’t see it here, for example, but the ‘private’ variable, _contacts, gets its values from a method found in the Controller: Contacts.getContacts() ContactListPage Build() function is the app’s View I’d put up its original version, but you’ll get lost in the code. Go look at its original if you want to make a comparison. Note, I did put in a Dissmissible widget (red arrow) in my version so to easily delete contacts. The original doesn’t have a means to delete contacts, and in my version you can see at a glance, what field is displayed and ‘deleted’ with a swipe! Github Where‘s this Dismissible Discerned? I may be getting ahead of myself a bit here, but that red arrow is introducing you to a very important approach applied here: The Controller is not only determining ‘what’ is displayed, but ‘what’ you can do with it. To a degree, this approach has the Controller take up what would be the View’s job and presents the data in a certain fashion (i.e. in a TextFormField, in a Text, and or in a Dismissible.) As you saw in the class, , there are a mess of ‘Field’ classes being defined. It is in this class, Field, where you will find the method, . ContactFields onDissmissible() onDissmissible() The Getter Gets It The method above actually calls the , dismissible. It is the that returns the desired Widget (in this case, a Dismissible) to the variable, newWidget listed above. getter getter get dissmissible Talk About Flutter Clutter As you see above, there’s a lot going on. Libraries are designed to make the lives of developers that much easier, but as a consequence, they tend to get messy themselves (having a lot going on in the background.) In this case, all the parameters associated with the Widget, Dissimissible, are made available to the user to use… or not. If not, the library supplies other values or functions. Doing so allows for options, and developers love options. For example, doing so allows the us to ‘clean up’ the code a little bit in the example above (beside the big red arrow.) Note, that example has two anonymous functions being passed to the function, . One for the named parameter, child, and another the named parameter, dismissed. onDismissible I mean, this whole exercise was to reduce the practice of passing anonymous functions as parameters, remember? Well…let’s do that. Boom! ContactListPage build() function Where’d Everybody Go?? Pictured above is the same function first displayed with the method, . It was used with its named parameters: child and dismissed, but now they’re all gone?! Replaced now with the item, ‘Contacts.list.displayName.dissmissible’. Where did they go? Take a guess. If you guessed they’re now in the class, , accessed by the , displayName, you’d be right. build() onDismissible DisplayName getter Class DisplayName The class, , first introduced to you now has two new implemented methods. Each overriding methods from the parent class, Field: and . That particular ‘logic’ is now embedded on the ‘Controller side.’ DisplayName onDismissed() onChild() MVC Means Manageability It results in the ‘separation of work.’ Picture a team of developers were working on this app, and one developer was assigned the ‘Contact Data’ aspect of the app. He’s not even given access to the build() functions! He does his work in the Controller as it’s the Controller’s responsibly to provide the data to the View (i.e. ). Thus, he’s only to provide the API (the public properties and functions) to the ‘UI’ team needed to access the ‘Contact Data.’ No problem. In this particular case for example, he gives them this: ‘Contacts.list.displayName.dissmissible’. the View can ‘talk to’ the Controller Done. It took a little more coding, but there you are. As it is, I prefer the former implementation over this one. It’s just a small little app, and I feel the separation of logic need not be that pronounced. Regardless, the point is you’ve got options, and we developers love options. Right? The Field Class So let’s take a further look at this class, Field. As you may have guessed by now. It’s a library I’ve created to make my life as a developer that much easier. It makes my code (code in my functions) that much cleaner. When the Controller is to provide a specific data field, it can do so with a Widget most appropriate for the situation. It can be a TextFormField, a Text, a ListTile, a CheckBox, and a few others. The list of Widgets is finite, but is growing. Like any good library file, it does a lot of the grunt work for you. build() The Irony Look at me. I started this article maybe complaining a little bit about the list of parameters found in Flutter, and I end up making a class library accepting some 77 parameters. And there’s likely going to be more to come! Hilarious! fields.dart The Point To All This Anyway, do you see why I did that? On your next project, you’ll have a data field from a database, and you are to display that data field in a TextFormField, a ListTile, a CircleAvatar, and maybe even in a CheckBox. On top of all that a Dismissible is to be implemented so that data field can be deleted with a swipe of a finger on some other screen down the line. The point is, define one Field object passing all the necessary parameters for all those Widgets, and you’re done. Get it? You now have a Field object you can apply to a number of screens throughout your app. What do you think? Widgets? How Many Widgets? As of this writing, the Field class accommodates the following Widgets. Again, more are likely to be added. TextFormFieldTextRichTextListTileCheckBoxListTileCircleAvatarDismissibleCheckBox So What’s The Real Point To All This? So, you can deduce that the Field class is still a work in progress. It’s in a file under the directory, , but you can see it’s not alone. You see, the Field class is merely in a utility file called Fields.dart inside a even bigger repository. One that holds my next package release, . Utils mvc_application The Bigger Picture In my development, I’ve slowly but surely been making my own little ‘application ’ so to make my life easier with each subsequent project. Developers tend to do that of course — build up their toolkit. framework With MVC_Pattern comes MVC_Application I was pleasantly surprised with the release of the package, . This package applied the 40-year old MVC design pattern to your Flutter app, and it received a receptive response when released. I saw a need, and as it’s my chosen design pattern for most of my apps, it was nice to see many still appreciate the ‘grandfather of design patterns.’ mvc_pattern As time went on, me working away, my ‘toolkit’ has grown. Now the intent is to release my current framework, , as a package. As it is, it simply works on top of the package, but includes a number of other libraries I’ve written and use in development. This includes some I’ve already publicly released and documented in past articles: mvc_application It won’t be tomorrow, but soon. mvc_pattern What’s My End Game So, what’s my end game to all this? As it stands, I’m just contributing to this fledgling Flutter community. Use it or not. Take what you want from it or not. Admittedly, in the end, it doesn't hurt to build up one’s profile a little bit. After all, this is my how I make a living. So what does the future have in store? Again, I’m looking to release the package, . After that? Oh I don’t know…. ? mvc_application mvc_enterprise Cheers. → Other Stories by Greg Perry Questions?
Share Your Thoughts