Flutter + Source Generation: The birth of a Magical Widget [Part 1]

This two-part article will discuss everything you need to know about the Magical Widget Flutter package. How it was born, what it offers, and how to use it.
If you are the type of readers that searches for keywords at the beginning of an article, fine, take these: super easy to use, very simple to understand, very powerful, source is auto-generated, Manipulate your UI widgets so easily, BLoC state management, and you should know this if you are a Flutter programmer 😌.

I am tempted to start the story of my newborn package — the Magical Widget, from the beginning, so bear with me for this introductory article where I share my personal experience as a Flutter developer. If you are absolutely in a hurry, and want to get your hand dirty, just skip to the second article where I discuss how to use the package.

As you may have noticed, the title contains two tempting words, Flutter is the first one, and source generation is the second.


Flutter

I discovered Flutter a couple of months ago, when I researched mobile cross-platform frameworks to develop my new app. Back then, I really fell in love with the framework, its uniqueness, its concepts, and its features. Therefore, I started experimenting and learning this new framework, but to be honest it isn’t a walk in the park. It has a learning curve to it, especially if you are new to Dart and reactive programming, but nevertheless it is absolutely worth it. I see a bright future for this framework.

Enough learning about Flutter, time to start developing a real app. As you might have guessed, learning something on a conceptual level doesn’t mean anything if you can’t do something on a practical level. This is coming from someone with a PhD by the way, so I have a bit of experience in this area.


I was on the first screen of my app, and I had a lot of interactions between UI widgets (the screen and the interactions are shown at the end) like this :

  • When a text field has more than 4 characters a button which was disabled should be enabled, and the inverse is true, less than 4 characters, the button should be disabled again
  • When a button is clicked other UI widgets need to be shown on the screen
  • Sometimes a progress indicator need to appear
  • Sometimes an informative error message should pop depending on the context
  • A button to reinitialize the UI state is also required and so on

First I used the famous setState() function to handle the state of the screen. Back then, I said to myself: the page only contains straightforward interactions and I can do it with this function, but, Oh I’ll be damned! 
My first screen, even though it is simple and doesn’t contain the heavy blocks of my app, thanks to setState() it started to look like hell, gibberish texts here and there. 
In addition to this, the app would always crash and complain about something related to setState(). Flutter didn’t really offer helpful error messages to help me pinpoint the problem, but at that level, I didn’t blame it for not understanding my code, as I didn’t understand it either 😄.

I took a step back, removed every single setState() function from my code, as I do hate this function now and you should too. Then I started researching BLoC (Business Logic Component) as an alternative mechanism to managed states. After all, BLoC is the method that Google recommends.

For someone new to reactive programming, BLoC was not so easy to grasp at the beginning, especially with overwhelming technical terms like: Observable, observer, subjects, streams and so on. Yet, what matters is the programmer mentality, and so I managed to understand it at the end. 
Afterwards, I used BLoC in my code, and it worked like a charm. My code was easy to read, test and debug, my presentation layer is separated from my business logic, and it just felt right, everything was in place.

I started to tweak my code here and there, doing some refactoring and optimizations, like encapsulating code that I will reuse and so on. I mean these normal stuff that every developer would do.

After many tweaks and optimizations, I found myself creating a simple yet powerful pattern that could help to manage widgets’ states among all my app screens, in an intuitive and easy manner.
First, I wanted to expose this pattern as a reusable function in my app so I could use it in many screens. Then I though that I should create this pattern as a separate package so I could import it into all my Flutter projects later on. However, when I was at the point of doing it, I even saw a pattern in my pattern, and then I said why don’t I automatically generate the source code of this pattern, so other Flutter developers could take advantage of it with minimum efforts.

Thus, this brought me into source generation.


Source Generation

I really don’t have much to share here, because I am not an expert nor a contributor to the source generation package. Yet, after diving a bit into this framework and learning some of its capabilities, I just want to exhibit my admiration here.

The source_gen package is one of the coolest packages in Dart that could help you to do meta-programming with ease. The only drawback was that it lacks a lot of resources. The package by itself is really powerful, but there is no resources to help you understand it and to get you familiarized with its API.
Therefore, I was obliged to inspect its source code, and to learn its API usage from the GitHub repository. At the end, the most important thing is that I learned enough to create what I wanted, and in case I missed anything, contributions are always welcome.

Given the scarcity of resources when it comes to the source_gen package, I took an oath that I will develop a couple of Medium articles to help developers take better advantage of this great package.


Magical Widget

So far I shared my experience with you, how I started, what brought me here, and what are the secret ingredients to my magical widgets.
Of course by now, you are wondering what exactly is a magical widget, and I will tell you right away.

The magical widget package allows you to defined all your UI controls in an enum, annotate this enum with a specific annotation, and Voilà, the magic happens. You can now control and update the state of your UI widgets with two simple methods changeUIElement(value, control) and changeUIElements(values, controls). That is literally it — Of course in addition to other code that you will usually write when you want to use a StreamBuilder.

That was rather an ambiguous statement, I know, but I will not discuss in details how the package works in this article, I will leave this to the second part where it gets a bit technical.

I told you about the package, but let me show you what you could easily do with it. Let us suppose that this is my enum:

@Alakazam()
enum UIConfigTyle {
enableSendBtn$bool,
enableContinueBtn$bool,
enableProgressIndicator$bool,
enableErrorBox$bool,
alreadySent$bool,
enableMobileTxt$bool$true,
mobileNumberTxtField,
verificationCodeTxtField,
countryPickerField$String$Lebanon_00961
}

Now remember that you could add as much UI controls as you need to this enum, no limit. Whatever you need to control your UI the way you want it to be controlled.
Don’t give much thought about the syntax of the elements within the enum, it is basically a name, a type, and a default value, all separated by a $ sign. These details will be discussed in the second article.
With just that simple enum, annotated with Alakazam, I can very easily get a screen with such interactions:

Enable/Disable Button based on Number of character in the text field. Choosing a country change the text field
Show/Hide UI elements. Dynamic error box. Clicking on wrong mobile number will clear the state.
Dynamic and context-dependent error box

I created my widgets as if I am creating any Flutter graphical interface, and I used StreamBuilder like you would with any BLoC application, but this time everything was magically connected, and I can manipulate my UI with ease.

So just writing the enum and adding one magical annotation will bridge everything together behind the scene. I am not exaggerating, the Alakazam annotation is that powerful. It saved me a lot of time, and I believe it will save you time too.
It allows you too just focus on building your graphical interface, the code for state management is taken care of, and the complexity of using BLoC has just been evaporated.

Now you saw what this package is capable of, simple enum will generate code to orchestrate complex UI interactions and state management. Next, I will discuss with details how to use this widget in the second article, so I hope you are motivated enough to follow along😊.

The GitHub repository of the project could be found here.

To read part two of this post, see: