A simple notes app with Firebase Firestore and Provider in Flutter 2.0 (Part 1) — Designing the home screen

Prashant Goyal
9 min readMar 18, 2021

(Edit: Part 2 of the series is here)

I have been hearing a lot of praise about Flutter on multiple online social media platforms and from many of my friends. Though I did not have an extensive background in Application Development, I wanted to see what all the buzz was about. So after watching the Flutter Development course by The App Brewery, I decided to make a simple version of the Google Keep app that I use on an almost daily basis as my first app. This app is supposed to be my “Hello World” to the world of Flutter. Well, the “Hello World” that I created on my own. I did create a few apps as part of the course.

This is going to be the first part in a series of tutorials wherein I will create an application for taking notes using Flutter 2.0. I plan to incorporate the following functionality into the application:
1. Adding, editing and deleting notes: Each note will have a title and some text content. Also, the user should be able to specify a label colour for each note. The colours choices will be prespecified and the user must choose from one of them.
2. Search functionality: The user should be able to search for a particular note by either the title or the note’s content.
3. The ability to share the note’s content with external sources at a tap of a button.
4. A simple theme switcher that allows the user to toggle between light and dark modes.
5. Offline storage: The notes must persist between application restarts.
6. Online synchronization: The user must be allowed to upload all the notes using an email password combination to the cloud. Whenever the user reinstalls the app, they should be able to get the old notes back using the correct email password combination.
The complete development process is done using Android Studio on a Windows machine. I do not own any Apple devices. So, the application is not tested for iOS.

If you are interested directly in the source code, here is a link to my Github and here is the direct link to the repository. I confess, I also prefer to first look at the source code or have direct access to the source code to understand the working better.

Alright, before we begin, let me first put this out there:

I am not a UI designer.

The application’s UI is based on what I saw on Google Keep and I hacked together a basic design in Figma that seemed appropriate to the functionality that I wanted to incorporate into the app while being true to Google Keep’s design scheme.

With that cleared out, let’s begin.

Starting with a clean slate

First of all, I am going to christen my application with the name: NoteNow

I am going to assume that you already know how to create a new Flutter project in Android Studio. If you do not know how here is a link to the official guide by the Flutter team.

When you create a project, there is going to be some code for a simple counter app in the lib\main.dart file. Just go ahead and remove all the code and make sure you have the following contents in that file:

import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'NoteNow', // This is the name of the application.
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Container(),
);
}
}

If you run the app with just the above code, all you will get is a black screen. But, we do not want just a black screen. Right? We want an application that will allow me to take some notes and write stuff down. Here is a screenshot of what I have in mind as the final product:

The final look for the NoteNow application
The final look for the NoteNow application

All the Dependencies

Out of the gate, let us put all the dependencies we will use in the app. Normally, you add a dependency as required but I have already created a functional app and hence, I know about all the dependencies that we will need. Therefore, make sure to add the following dependencies in the pubspec.yml file:

dependencies:
flutter:
sdk: flutter


# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.0

# UI
flutter_staggered_grid_view: ^0.4.0-nullsafety.3

# Functionality
url_launcher: ^6.0.2
provider: ^5.0.0
share: ^2.0.1
uuid: ^3.0.1

# Local storage
shared_preferences: ^2.0.4
sqflite: ^2.0.0+2
path_provider: ^2.0.1

# Cloud Sync
firebase_core: ^1.0.1
cloud_firestore: ^1.0.1
firebase_auth: ^1.0.1

Designing the HomeScreen

A breakdown of the design

A very basic look at the widgets that need to be in the HomeScreen

Just looking at the design, we can deduce that the screen will have a column widget. No need for an AppBar on the HomeScreen (this will be the name of the home widget). The top of the screen has a FloatingSearchBar. You know, to let the users search for their notes? We will come to the layout of the FloatingSearchBar later. After the search bar, there is a Grid View vertically below it and a simple Floating Action Button. The Floating Action Button is going to be a part of the Scaffold widget.

Now that we have an idea about the way the components need to be strutured for the HomeScreen design wise, let’s start coding it!

Creating the HomeScreen

First of all let’s begin by editing the MyApp() widget in the lib/main.dart . We will be designing the app primarily in the dark theme and then modify the colors for light theme later. Begin by creating a file with the following path lib/constants.dart . This will contain some colors, styles and common widgets that might be used at multiple places within the app.

The constants.dart file will contain the following code for now:

import 'package:flutter/material.dart';

// The background color for the app when using the dark theme.
const kDarkThemeBackgroundColor = Color(0xFF2E2E2E);
// The background color for the app when using the light theme.
const kLightThemeBackgroundColor = Color(0xFFFAFAFA);
const kPurpleColor = Color(0xFFBB86FC);

Then let’s use these colors in the lib/main.dart file to specify the app theme:

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'NoteNow', // This is the name of the application.
theme: ThemeData.dark().copyWith(primaryColor: kDarkThemeBackgroundColor),
home: HomeScreen(),
);
}
}

The above are the contents of the lib/main.dart file. The HomeScreen() widget is the actual widget that will hold all the design and functionality elements. So, let’s go ahead and build that. Create a new dart file under the following path: lib/screens/home_screen.dart . This will hold a Stateless widget with the FloatingSearchBar and the GridView with a summary of the notes. Put the following code in the newly created file:

class HomeScreen extends StatelessWidget {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>(); // This will be usefull in the FloatingSearchBar for opening the Nav Drawer

@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.add,
),
backgroundColor: Color(0xffBB86FC),
onPressed: () {},
),
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: FloatingSearchBar(scaffoldKey: _scaffoldKey),
),
Padding(
padding: EdgeInsets.only(left: 20.0, top: 4.0),
child: Text(
"Your Notes",
style: TextStyle(fontSize: 24, fontWeight: FontWeight.w600),
),
),
SizedBox(
height: 10,
),
Expanded(
child: Container(
color: Colors.white60,
child: Center(
child: Text("The gridview here"),
),
),
)
],
),
),
);
}
}

After using the above code, this is what the app will look line when run on a mobile device:

Creating the HomeScreen like Lego blocks!!!

The screen is starting to take up shape. This is what I like a lot about Flutter. The design process is really simple and with a few lines of code, you can accomplish a lot. In the code above, the main layout basicallystarts with the Column which is a child of the SafeArea widget. The Floating Action Button is part of the Scaffold and will be used to open a screen that will allow the user to add a new note.

Now that we have given a general area to each widget, lets start by creating our Gridview to show the user’s notes.

Scattered GridView — Resizes grid tiles according to the content

If you look at the final app image included earlier, you will notice that the GridView tiles are dynamic in height. Their extent changes based on the content of the tile. This can be easily done using the following awesome package: flutter_staggered_grid_view | Flutter Package (pub.dev). The package supports variable configurations with regards to the number of columns and the row size, but for our purpose, we need a configuration that has a fixed number of columns and a variable number of rows for each tile. Hence, it is suitable for us to use StaggeredTile.fit to determine the extent of each tile.

To incorporate the StaggeredGridView into the application, we do not need to specify it in pubspec.yml as we have already done it earlier. Let’s just start using it to create tiles with variable sizes. In the code for the HomeScreen above, find the Expanded widget and replace it’s child widget sub-tree with the following:

StaggeredGridView.countBuilder(
crossAxisSpacing: 12,
mainAxisSpacing: 12,
padding: EdgeInsets.symmetric(horizontal: 14, vertical: 8),
crossAxisCount: 4,
physics: BouncingScrollPhysics(),
itemCount: 16,
itemBuilder: (context, index) => Hero(
tag: 'note_box_$index',
child: GestureDetector(
onTap: () {},
child: Container(
color: Colors.white38,
height: index < 50 ? (index + 1) * 10 : 50,
),
),
),
staggeredTileBuilder: (int index) => StaggeredTile.fit(2),
)

The other properties are the same as the standard GridView, but the magic for resizing based on content lies in the itemBuilder and the staggeredTileBuilder properties. The staggeredTileBuilder takes a function that returns a StaggeredTile object from the flutter_staggered_grid_view package. We are using the StaggeredTile.fit(2) to tell the widget to use 2 columns for a grid tile and change the vertical extent based on the content of the tile. The vertical extent is being controlled by the container in the itemBuilder . By specifying the height as conditional based upon the index of the tile, we are controlling the vertical extent of each tile to a maximum of 50 pixels. Attached is a picture of what the HomeScreen looks like when the app is run in this state.

Reflecting on what we have accomplished

I think we have progressed a lot up until this point. We have created the bulk of the UI for the HomeScreen. We know what our goal is with regards to the functionality. Believe me, defining the goals are super important!

Let’s wrap up this article at this point. In the next one, we will be focusing on creating some models for the note object that will carry all the data in the application. Using the provider package and the concept of an Application’s State, we will lay some ground work that will make the functionality of the application extremely easy to implement in the later stages. Also, we will create the UI for the Grid Tiles. If at any point during this article and any future articles, be on the lookout for links to the Github repository that I will definitely include for each project. Having access to the complete code makes it easy to figure out the solution if something is going wrong. Here is a link to the completed code for this application: NoteNow Github Repository.

Thank you for reading and stay tuned for the subsequent parts of this series!

--

--