Getting Your Hands Dirty with Flutter: Project Setup + Authorization

For the last couple of months I’ve been looking for a cross-platform mobile framework to implement some of my ideas.
Naturally, React Native was the first thing I tried. It’s rather easy to work with. In fact, such combinations as Redux-Observable and Epics can actually help you build great apps. However, it turned out not what I expected it would, so I left the idea soon after completing the SignIn/SignUp part.
The next thing I decided to try was Flutter, Google’s cross-platform mobile framework written in Dart. I learned about it in 2017, at the GDG DevFest in Ukraine. Although the framework was still in alpha then, a guy on the stage said it was stable enough to build thin client-server apps, so I took his word for it.
The first project I wanted to develop was a simple booking app for the lounge area at our office. I wanted to automate the process of booking the ping-pong table, PlayStation 4 and the other cool things we have there. Through a series of articles, I’m going to take you through my process of turning this idea into reality with Flutter.
Setting up a project
If you’re planning to use IntelliJ IDEA with the Flutter plugin like I did, my advice is that you do not create the project within your IDE, but do it through the command line.
I can’t really tell why, but there were a lot of issues adding various Google dependencies like Firebase Auth and GoogleSignin to the iOS app. When I created another project through the command line, everything went just fine.
I wanted the app to have a simple intuitive flow, and Material Design helped me achieve just that. As a main widget, I went with the combination of: MaterialApp and Scaffolds, since they already have a float action button, tabs and all that stuff. For navigation, I used Navigator and Routes. The approach is actually similar to what you’d do in React Native, but there are some peculiarities that we’re going to discuss in the next part. Also, I didn’t want the app to go in the landscape mode, so I used SystemChrome.setPreferredOrientations. So far, everything looks like this:
There are two main types of widgets in Flutter — StatefulWidgets and StatelessWidgetes. A concept similar to React, where stateful widgets have a global state, and all of its properties can be bound with children widgets. Hence, any updates of the global state properties re-render the widgets bound to them.
First, I decided to create a basic screen widget that would display the loading process, contain the app’s bar title and logout state, and then extend it to the rest of screen widgets. What’s great about Dart is that it’s generics and extending work exactly the same as they do in Java. Here, see for yourself:
There are two bool flags that decide whether to show the loading indicator and the logout button or not, and a string properly for the appbar label. Nice and easy.
Authorization
The next thing I implemented was a Welcome screen, which checks whether a user is already registered, and then proceeds to either Sign In, Add Profile or the Main Screen. The state class has an initState() method, and it’s a perfect place for such a task. As the data fetching has to be done asynchronously, I added the Future. It’s very similar to Promises in JavaScript, as it uses a then() method to catch the results of asynchronous operations, and handles errors with catchError().
As every screen needs to be opened without adding another Welcome screen to the backstack (so that users don’t come back to it whenever pressing the ‘Back’ button), I implemented the Navigator’s pushReplacementNamed method.
Here’s the auth model. Take a look at the Future async-await blocks. If you’ve come here with a background in Android development, you know that such constructions are used in Kotlin’s coroutines. If you’re from JavaScript, you know that ES6 offers the same async-await blocks. If you know neither — just trust me, the magic works.
Another important note: use dictionaries for constructor arguments (like DataClasses in Kotlin), so that you don’t have to initialize the unnecessary fields with null or stubs.
I added a very basic rest-client just to get a feel of this part of Flutter’s feature-set. You can try this tutorial for networking, but I didn’t like it very much, and ended up using an HTTP package. Here’s what I got:
Sign In and Sign Up
First of all, I created a stateful widget, where the state extends our base state (which was mentioned earlier in the text). If you’re using IntelliJ IDEA, try and make use of its awesome widget generator, which you can read more about here.
For the screen state, I created three TextEditingController instances for email, password and confirm password inputs, and a enum field to handle the SignIn/SignUp widget state toggle. For those of you used to rich Java enumerations, I have bad news — Dart’s enumerations are just enumerations: no constructor arguments, no methods, nothing. It’s devastating, I know.
By now, my screen state initialization looks like this:
Here’s how the UI in iOS:


And here it is in Android:


I wanted to get three text inputs and two center-aligned buttons, one under another. To achieve this, I used Center class as a main widget. It takes up all available space, accepts only one child and aligns it in the center of itself. Inside, I used Column, a widget that displays its children in a vertical array. Also, you can see that the _signState state property decides whether to show the password input confirmation or not.
Below, you can see how to add an input widget. I’m giving you only one example, because the approach is very similar:
As you can see, alignment, paddings and margins aren’t numeric values, so you might want to read up about them a little before using. And I’m not being condescending here — they are tricky.
In order to create a bordered frame with a corner radius, I added BoxDecoration to the Container widget, which wraps the input. Container is similar to a div in HTML.
Lastly, I added a TextField with a password hint, input type and the controller we’ve mentioned before. The only difference between this input and the password input is that we hide the input with dots by adding obscureText: true to TextField in the latter.
Confirm button and the SignIn/SignUp state toggle
Nothing too complex here: the onPressed property doesn’t take a function, but does take VoidCallback. The main difference is that it cannot accept arguments and doesn’t return the result.
I created a first-class function in a separate file to make building AlertDialogs more convenient. Here it is:
The following method should be refactored, I know. But it’s only a pet project, so I’ll do it later (read: never):
Here, you can see various validations with regular expressions and input lengths and alerts of the function we’ve built previously.
If the validation is successful, I clear the inputs with their controllers, set the screen state to loading, and asynchronously authenticate the user with the FirebaseAuth. If the authorization is successful, I navigate to either Add Personal Data screen or Main screen. If it isn’t, the app takes the user to the Error handling screen.
In the next part, we’re going to discuss the specifics of UI (such as linear and grid lists, handling flex of rows, columns etc.), using Expanded and Flexible, and using Firebase Firestore with Flutter to create rich applications.
You can find my project’s code here. Thanks for reading and see you later!