Going from scratch to a full-blown Flutter app in two days
In this article, I’ll give a detailed account of my experience of building an app for a development hackathon with just two days of work. I will talk about the choices I made, the tools I employed and all the catching practice I indulged in(pj, I know).
For a framework, I chose Flutter to be my “companion”. Many of you will reprimand me for not going with React instead and the rest of you are knowledgeable enough.
I chose Firebase as the back-end to my app, for no particular reason; Azure and AWS have good alternatives as well. Later, I also added an SQLite database to a second version of the app (more on that later). I used Google’s Material Design guidelines to shape the UI for the app while taking some bits from the iOS side as well (example, for the custom tab bar).
For an editor, I had Visual Studio Code as my workhorse; light, fast, auto indentation, color coding, you name it (plus, Microsoft 😁)
Idea Behind The App
“Giving back”. This was the theme for the hackathon which had problem statements inspired by the urge to help others through technology. Out of the 6 problems provided as a starting point, I found one particularly intriguing.
It is one of those moments when you look at something and instantly feel an urge to connect with it.
A complete description of the purpose of the app can be found here, where I lay out my pitch for this project.
I had my idea ready within a few minutes of the release and with a complete breakdown of all the features I envisioned the app to have, I did two very important things:
First, I segregated the feature list into two parts: one part comprised such elements which I was sufficiently confident in implementing by myself and also in a short timeframe; the second part had features that I would have to invest time in, to be able to implement according to my vision.
Second, after realising what features to work on first, I chalked out a timeline which would enable me to complete not just the app but a PowerPoint presentation, the pitch video that I linked above (which is also the one you must be done watching by now) and demo+screenshots of the working prototype.
Friday, 10 P.M.
I got to work right away. I designed the basic layout of the app; the different screens that had to be present, the drawer & what options should it have and also the tab bar. At this point, I just have a skeleton of an app which does nothing and is not responsive at all.
Next, I take up the Tasks screen. I laid out the “Ask-Questions” widget that prompts the user to answer questions once in a day.
Here, the answered variable checks if the user has clicked on the “Yes” button already and the timeUp variable affirms that it has been 24 hours before the askQuestion widget is displayed again. Inside the timeUp method, I’ve made use of a DateTime instance to get the current date and month and then I compare the older value stored in the database with the value of the current date and month.
After the askQuestion widget was done, I laid out templates for the particular tasks that I would assign to the users.
I used a ListTile with the title as an Image widget and the task as the subtitle, to make the feed visually appealing. I wrap this widget in a GestureDetector to allow a ‘double-tap to dismiss’ functionality for each tile.
The isDepressed member checks whether the user is predicted to be depressed presently and the notDone member is true when the task is still incomplete. I have commented out those lines so that the tasks show up at all times, for illustration purposes.
The research I did on the topic pointed out one primary idea: sadness and depression are different. I envisioned an algorithm that considered data from the past week and if it found that the client was consistently meeting less people and also scoring poorly on the happiness and productivity poll, he/she would be classified as being in a depressed state and consequently tasks would be suggested. On the other hand, if a client kept seeing a large number of people but still scored low on the happiness poll, then it would be safe to assume that the person is going through a tough time and is not in depression.
Before I retired for the day at 3 a.m. , I laid out my plan for Saturday: implement a back-end to store all user variables and complete the UI for the rest of the screens.
The first thing I did? Set up Firebase for my project and configure the Android version of the app with it. If that sounds new to you, check here.
For the choice of a database, I went with the new Firestore which, for those of you who expected Realtime DB, is Realtime DB but better. I also enabled Firebase Authentication to allow Google sign-in. After that was done, I jumped to the code.
I created a new Dart file and added methods for signing in with Google.
Then, I quickly moved to implement a very basic login page where I created an authentication listener to look for any login events. If the user was logged in successfully, I sent them straight to my home page along with the user id of the user.
I implemented a cloud function to automatically index all my clients in an ascending order of user Id. I used a Firestore instance created through the user id that was passed from the login screen, in every file that required use of database variables. An example:
Here, answers is the name of my collection and each individual document inside it corresponds to a user.
To build the UI using variables from Firestore, I made use of StreamBuilder; It is a proven way to build dynamic UIs based on values from a stream but this is where I ran into my first major roadblock in this project. While running the Tasks screen, I encountered “method called on null” exceptions repeatedly.
On careful debugging, I figured out that only the variables that had changed in the database were being sent in the DocumentSnapshot that I was relying on to build my UI. As a consequence, the logical checks on the other variables started throwing exceptions.
To remedy this, I created a Map to store the status of variables in the current DocumentSnapshot and only those variables would be checked for which the value corresponding to their key returned true.
The next obstacle, however, would leave me scratching my head for six full hours; yes.
On running the code for the Android version, I ran into the following formidable gradle error, for which I could find no fix anywhere on the internet. Every hack that the Stack Overflow gurus suggested was obliterated by this one exception.
Launching lib/main.dart on Android SDK built for x86 in debug mode… Initializing gradle…
Running Gradle task ‘assembleDebug’…
FAILURE: Build failed with an exception.
* What went wrong: Could not determine the dependencies of task ‘:firebase_core:compileDebugAidl’. > Could not resolve all task dependencies for configuration ‘:firebase_core:debugCompileClasspath’. > Could not find com.google.firebase:firebase-core:.
Required by: project :firebase_core
I had almost lost all my patience but I refrained from giving up because I had full faith in my idea and above all, limitless desire to not let this opportunity go waste. I had a chance to be the real developer I always strived to be and here was my challenge.
I sat back and went through Android documentation looking for possible causes of failure. One page talked specifically about how AndroidX had compatibility issues with Flutter. “Aha!” I recalled that I had upgraded to AndroidX last year and that is where the fire was. I reduced the dependencies' versions to pre-AndroidX levels and (loud cheer) my app successfully launched! At the end of this slugfest, I had lost eight hours to unproductive work and had almost every other screen left, to implement.
I took up the Questions page next.
First, I visualize what the page should look like; things to keep in mind: it should be easily answerable (implies, no text fields) and it should cheer the user up (colors, a lot of color).
Second, I look for plugins that will speed up my work of implementing a slider for answering questions. Luckily, I found one pretty fast.
I designed the UI very rapidly; added the slider, configured the colors (I implemented a gradient that synced well with the slider value).
It was not until late Saturday night, when I checked my Nokia that I found I would have one more day to bring my house in order because the deadline had been extended. Nevertheless, I made it a personal goal to have the app working by the end of Sunday.
With the cloud integration working, I moved to implement my Dashboard which took values from the cloud, ran a check and displayed insights to the user. Building the UI had, by then, become a cake-walk. I implemented features for the rest of the pages as well.
When put to test, however, the code threw up another exception, this time about a “failure in performing transaction; operation timed out”.
I spent a significant amount of time trying to rectify this issue, to no avail. At this point, I had a Plan B which was to scrap all cloud integrations and make a “stateless” app just to demonstrate basic UI features. Of course, that was something I wanted to avoid as it would take away all life from this app.
Close to midnight, I had given up on the cloud and was working on my Plan B when out of nowhere, I conceived the idea of an SQL Database.
I researched on Flutter and SQL integration and within a couple hours, I had a roadmap for the new incarnation of my app. I wrote down a Database class, added methods for adding, updating and deleting clients. I also hastily assembled a Model class that represented a single client. By that time, I knew sleep wasn’t an option and was very definitely missing my Monday class 🤷♂️.
I replaced my code with SQL integrations and tested basic features to make sure I was going in the right direction. By five A.M. I had an SQLite powered app ready which only required polishing, images and other visual touches.
I looked for crisp infographics to drive the visual appeal for my app and even after I landed good images for the app, it was a pain to actually make them load. The problem? YAML’s indentation rules 🤦♂️.
As the day progressed, I tightened some screws, plugged some leaks and made the app ready for showtime. I went out and shot the pitch (which you have seen by now) in a single take and tried to put as much information as my drowsy self possibly could. I then put together a PowerPoint presentation explaining the app’s idea and implementation and finally I made the submission well before scheduled time.
This hackathon has been an exhilarating experience. It brought out the best in me and pushed me to the very limits of my productivity. Every exception was a challenge that I had to fight independently and with the full valour of my soul. In the end, I felt a sense of satisfaction and fulfillment that I had been craving for quite a long time then.