DEV Community

Kaelan Mikowicz
Kaelan Mikowicz

Posted on • Updated on

Mobile app in 4 days with Flutter and Parse

I'm an organizer for HackDavis and my job is to write software: things like our website https://hackdavis.io, our applications review platform, and various scripts to automate some of our workflows. This year we wanted to build a mobile app that would allow participants to collect badges for attending workshops, and compete on a leader board with other teams. Another team member set off to build the iOS version in Swift. Enter my dilemma:

Finding an API

Way back in 2012 I built an Android app, once.

It was a terrible experience, 3 Java classes just to make a simple list view.

I was looking for a way to quickly build out this Android app without getting bogged down in Java API documentation and dealing with Android Studio and XML-based layouts.

I immediately thought of React Native. Having worked with React before I knew it would be a workable endeavor. I normally work with Vue, however, because it feels more natural to write and the documentation for React is bad, the documentation for React Native being unbelievably more abysmal.

So I searched for a new, shiny, fast, mobile development framework. That's when I found https://flutter.io/. Main Features:

  • A e s t h e t i c
  • Hot🔥 reload
  • "Native Performance"
  • Written in Dart?

Dart itself didn't look too hard, it seems like Javascript with static types but not like Typescript.

Also we are using Parse because the iOS developer thinks it's cool.

On with it!

Building an iOS app for Android

So I'm porting an iOS to Android, my immediate plan is to use widgets from the cupertino library in flutter, since they already incorporate iOS design. I figured that I would need to recolor most of the UI to match the screenshots below:



Here is what I was able to achieve using the cupertino library:



Login

Flutter provides a large number of widgets in its library. Some of the ones I used include the CupertinoTabScaffold, CupertinoPageScaffold for setting up the screens, and Row, Column, and Container for flex layouts on most of the text elements. The green information box on the Login screen was made using a CustomPaint widget to draw the arrow.

Coming from a web framework background, it is nice to see that there is an analogous concept in Flutter with StatefulWidget and StatelessWidget. Stateful widgets have lifecycle hooks and a setState method like in React/RN, whereas Stateless widgets render using props. I used these concepts to set up timers for the hackathon ending, and also to create components that would render in the lists on each page.

I then needed to style the UI to match the screenshots.

Styling is impossible

Styling in Flutter is pretty difficult, certain elements can be directly styled to alter typography and colors, but not every widget accepts a style argument. Also, adding padding to an element means adding a Padding widget as its parent. This makes the render function hard to read especially with multiple nested widgets. An example widget used in the app is this:

class LeaderBoard extends StatelessWidget {
  final List<Team> teams;

  LeaderBoard(this.teams);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Builder(
            builder: (context) => Container(
                padding: MediaQuery.of(context).padding,
                child: ListView(
                  padding: EdgeInsets.all(15.0),
                  children: teams
                      .map((e) => Padding(
                          padding: EdgeInsets.only(top: 10.0, bottom: 10.0),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: <Widget>[
                              Flexible(
                                  child: Text(
                                "#${e.rank} - ${e.name}",
                                style: (e.rank <= 3
                                    ? Theme.of(context).textTheme.body1
                                    : Typography.whiteMountainView.body1),
                                textScaleFactor: 1.2,
                              )),
                              Container(
                                  margin: EdgeInsets.only(left: 50.0),
                                  child: Text(
                                    "${e.count} Badges",
                                    style: Theme.of(context).textTheme.body1,
                                    textScaleFactor: 1.2,
                                  ))
                            ],
                          )))
                      .toList(),
                ))));
  }
}

As the example shows, there is a lot of configuration going on in the render method just in terms of styling, setting text scaling, wrapping components in containers and padding. This makes for a bad time styling applications. Furthermore, the cupertino library does not have a Theme widget like the material design library does. I would hope that the flutter team makes styling easier, like applying CSS rules to an entire set of widgets.

Since the cupertino widgets did not accept any type of style or theme props, I was having a hard time changing the background color of the screens. This was when I realized: I am on Android, I should be using material design.

After swapping out the cupertino library for the material library, I could style most of my components, and after a while I had something that looked like this:



I removed the top navigation bar because it seemed redundant, and added a FAB for adding badge codes. I also used a TabView with a BottomNavigationBar in order to implement the bottom bar. Usually the TabView is used with a tab controller, but the tab controller renders differently from a bottom bar. I had to implement the control logic myself using a few state variables.

Fixing the parse platform

Flutter is new while Parse Platform is old and discontinued, so you can imagine how few people are using both together. There are no official Parse libraries for dart. Thankfully there is a flutter-parse-sdk package for dart that I was able to use for the project.

It had bugs, and because the library was so minimal there was no workaround.

  • I used files in the "Classes" (Database tables) to store badge images, the SDK threw an error whenever it encountered a file
  • I couldn't login anonymously
  • Saving changes to the user did not update in the database

The Parse library on native Android was officially supported and had all my features, but the flutter - Android bridge is only for making method calls. I needed the objects to be represented in Dart so I could use it in the UI.

So I forked the SDK and implemented these bug fixes on my own. After a while I was able to get the library working for my purposes, and these changes are now merged into the sdk.

Fix User objects not saving, Add support for Parse Files, Anonymous Login #67

klanmiko avatar
klanmiko commented on Feb 02, 2019

Hi Phil,

I am using your sdk to develop an application for our hackathon participants. I ran over a few issues that I fixed and I thought it woud be a good idea to contribute back to this project. Here are my changes:

  • Fixed changes on User object not syncing to server due to missing session token when accessing API
  • Added the ability to login anonymously by providing "AUTH_DATA" POST data with a unique UUID. Can be extended to allow for facebook and twitter auth in the future
  • Added the ability to create a Parse file with a url and name and download the file to temporary storage
  • Fixed bug with ParseFile initialized to null _file value.

Let me know if these need work

Why are you killing my widgets?

Another thing that I noticed is that every time I switched between tabs I would see a lot of lag. I realized this was because the widgets were being rebuilt, network calls being remade, every time I switched between tabs. To fix this, I added an AutomaticKeepAliveClientMixin so that the tab view would not destroy these views when navigating.

But these views would still be destroyed, only when I went from screen 3 to 1 and then back to 2. I would see the content flash. Apparently, though it isn't documented, the TabView will destroy any screens in between if it has to jump multiple screens, this means that my app was having to still redo the network requests to render. This resulted in lag.

The solution, like in React, was to lift the state up. I ended up making each tab screen stateless and rendered the list data using props, this meant that my main widget was huge and had to load all of the data through the network. This was ok if it meant that the app would render without lag.

So let me know what you think. Have you used Flutter before? Do you like the framework? Would you like to learn more about Dart? I am interested to hear about other developers' experience with Flutter and Dart in general. I think it could be a good language to develop applications in.

Latest comments (1)

Collapse
 
klanmiko profile image
Kaelan Mikowicz

Thanks for the tip! I'll be updating my code with the formatted version.

Also I did look over the performance consideration stuff. I assumed that keeping the state near the leaf (on each tab) would make it render faster, I did not account that the tabs might be destroyed when switching.