Devblog 8: Taking another dive into FlutterFlow

In an earlier devblog I wrote about having tried FlutterFlow and why I decided to not use it for my pet project.

Well, it turns out FlutterFlow has added some very nice features last month, one of which made me reconsider FlutterFlow.

Together with a switch in mindset, I was willing to give FlutterFlow another chance.

What changed?

In February, FlutterFlow released a new update. The update addressed one of my major pain points.

The update adds the possibility to scope state to a page or component. Before the update, you could only use the global state. This became messy rather quickly when you had a lot of variables to store.

Having more control over your local state also allows you to be more conservative with your Firestore interactions, saving you money.

You can for example decide to first keep track of data locally, and only save to Firestore when the user explicitly presses save.

What about Directus?

Before I started using FlutterFlow again, I was working on authentication with Directus.

After I had set up the basic authentication flow, I started thinking about how to model my Scavenger Hunt data.

At that point, I concluded a document database like Firebase might be a better fit, at least for the game configurations.

Also realizing that I was spending a couple of hours a day for a few weeks just to get the authentication partially finished, made me see how easily Firebase was to set up.

Directus may still become a part of the project, but it will not be something I will focus on for now.

A different mindset

In my previous attempts to use FlutterFlow, I looked at it through the eyes of a Flutter developer. I tried to solve problems the way I would try to solve them in code.

In many cases, FlutterFlow will not be able to do so. If you're a Flutter developer, and you're going to give FlutterFlow a try, try to go in with a blank slate. Try to understand how FlutterFlow wants you to solve certain problems instead of comparing them to how you'd have done it in code.

Your Flutter knowledge will still come in handy. The way you build UI, with widgets, will be very familiar. While FlutterFlow comes packed with a lot of predefined widgets and actions, you're able to extend FlutterFlow with custom widgets, functions and actions. These are still written in Dart, so also here your Flutter developer skills have value.

My first custom action

For my project, I had to create a way to change the order of the destinations of a Scavenger Hunt. I could not find a built-in way to do this, so I decided to give a custom action a try.

The arrow buttons on the items in the list would swap the position with the item below or above it when pressed.

To create a custom action, you will have to define the parameters, and optionally a return type. You can then let FlutterFlow generate a template that requires you to fill out the body.

In my case, the input parameters were the original list of destinations and the index of the item that would be swapped. The result would be a new list of destinations. I decided to create two separate actions, one for moving the item of the given index up, and one for moving the item down.

We could write this code ourselves, but we can also tell FlutterFlow to write the code for us.

By describing what you want your custom action to do, FlutterFlow will provide a solution based on the parameters and return type that you defined for your action.

I told FlutterFlow to: "Swap the item with the given index with the item below it", and the code it generated was spot on, even handling the case where the index is that of the last item.

// Automatic FlutterFlow imports
import '/backend/backend.dart';
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/custom_code/actions/index.dart'; // Imports other custom actions
import '/flutter_flow/custom_functions.dart'; // Imports custom functions
import 'package:flutter/material.dart';
// Begin custom action code

Future<List<ScavengerHuntDestinationStruct>> moveDestinationDown(
  List<ScavengerHuntDestinationStruct> destinations,
  int index,
) async {
  // swap item from given index with item below

  if (index == destinations.length - 1) {
    return destinations;
  ScavengerHuntDestinationStruct temp = destinations[index];
  destinations[index] = destinations[index + 1];
  destinations[index + 1] = temp;
  return destinations;

So now we can use this action on the arrow buttons like so:

The first action is the custom action. This action will return the updated list of destinations. The next action updated the Firestore document.

That's it! We created and used a custom action with the help of AI!

What's next?

I'm currently focussing on the functionality that allows users to create 'drafts'. Drafts are editable Scavenger Hunts which have not yet been published.

Users will be able to update and test drafts until they are ready to publish.

So far I've got an overview of the drafts, and a way to create a new draft or edit an existing one. So far you can only add and remove destinations for a Scavenger Hunt, so next will be editing functionality.

Hopefully, I will be able to show a bit more about the app itself.

Bye bye!