/learn-flutter

🦋 Learn how to use Flutter to Build Cross-platform Native Mobile Apps

Primary LanguageDartGNU General Public License v2.0GPL-2.0

learn-flutter

https://flutter.dev/

What is Flutter?

Flutter in an open Source SDK for creating high-performance mobile apps for IOS and Android. The Flutter makes it easier for you to build user interfaces, while reducing the amount of code required to create and update your app.

Why use Flutter?

  • Flutter can be used to build cross platform native applications (Android, IOS, Desktop and Web) using the same codebase.
  • The Dart programming language used in Flutter is object oriented and familiar to most developers.
  • Development times are significantly faster than other cross-platform frameworks thanks to stateful hot-reloading and excellent virtual device support.
  • If we close the application when we open it again we can continue from where we were
  • Flutter has a complete design system with a library of Material UI widgets included which speed up the development process.

Core Principles

Flutter is designed for the creation of 2D mobile applications.

Widgets

In Flutter everything is a "Widget". A Widget is a UI building block you can use to assemble your app. In the following Gif the sample application contains a total of 6 widgets: flutter-counter-sample Image attribution: https://uxplanet.org/why-you-should-use-google-flutter-42f2c6ba036c

  1. The container widget starting on line 17 groups all other widgets in the layout.
  2. The appBar widget displays the text "Flutter Demo Home Page"
  3. The body contains a child widget which in turn has Text and a $_counter placeholder.
  4. The floatingActionButton is the button that gets clicked, it contains a child which is the icon. Examples of Widgets include dialog windows, buttons, icons, menus, scroll bars and cards. You can use one of the many built-in Material UI widgets or create your own from scratch.

A widget can be defined as:

  • Physical elements of an application (buttons, menus or bars)
  • Visual elements such as colors
  • Layout and positioning of elements on the screen using a grid system

Widgets are assembled in declarative hierarchy which allows us to easily organise the layout of our App as a series of nested widgets.

Screen Shot 2020-02-06 at 19 01 17

Screens are composed of several small widgets that have only one job. Groups of widgets are assembled together to build a functional application.
For example a Container widget contains other widgets that have functions like layout, placement and size.

Screen layout is controlled by combining a container and other smaller widgets.

There are some widgets that have no physical form within the application instead their goal and control some aspects of another Widget.
Like: padding, alignment, row, columns, and grids.

Layers

A Flutter layout can have layers to create a visual effect where certain widgets "float" on top of others to give them priority.

Screen Shot 2020-02-07 at 09 06 06

Flutter uses layers to represent visual hierarchy and relative importance or priority of each widget.

Building Widgets

To assemble our widgets into an application we use the build() function. e.g: Widget build(BuildContext context) { ...

For example, the appBar menu needs to be invoked using the build() function. It can then have other nested "child" widgets such as buttons or text.

User Interaction

A StatefulWidget widget, as its' name suggests, stores the state of the UI it represents. For example the counter widget stores the _counter variable which keeps track of the number of times the user has clicked the button. All user interaction that requires storing some data/input uses a StatefulWidget widget.

When the State of an object is changed, the setState() function should be called to update the UI. This in turn will invoke the build method which re-renders the widget.

Testing

As in all programming languages, frameworks or platforms the secret to a successful Flutter application is to test it extensively. Several tests should created included functional tests and UX tests which can help us discover and fix any bugs before users see them!

An application must have tested all functions, classes or tasks needed to run correctly without errors.

Widget tests are necessary to confirm that they are performing their intended function and correctly positioned in the layout.
Integration tests serve to test the application as a whole so that we can test the app in a real-world scenario.

To learn more about an example of using TDD: https://github.com/dwyl/flutter-counter-example

Dart Before Flutter?

Before you dive into Flutter you have to learn the programming language that is used to build Flutter apps, and that is Dart.

Flutter for Windows installation

Access the link and click Get Started

Flutter

Select the windows button and then click the "flutter_windows.zip" button.

Flutter

Extract the file and place the folder in directory "C:"
It's probably best to create a folder in the directory like this.

Flutter

This is the console that comes inside the folder in this case the Flutter console, can use to see which devices connected, create a project in Flutter.

Flutter

In order to access Flutter commands without having to open this console, we can use the Windows prompt itself we need to add Flutter to the environment variables.

You need to go to the bin folder and copy the path then go to the computer properties, then go to advanced system settings.

Flutter

Click on environment variables, then go to edit path and paste the path to Flutter.

Flutter Flutter

As you can see if you go to the windows prompt and run the command "flutter" it already appears.

Flutter

Now at the windows prompt if you run the command "flutter doctor" will check if there is anything left to install so that we can develop the applications with Flutter.

Flutter

If you need to install android studio here is the link:https://developer.android.com/studio
To install dart and flutter just go to the Android studio and press plugins and search for both.
After having everything installed just open the Android Studio that will appear "Start a new Flutter Project".

Flutter

Scaffold class?

Provides a framework which implements the basic material design visual layout structure of the Flutter app. Contais various functionality from giving an appbar, a floating button, a drawer, background color, bottom navigation bar and body.

AppBar

It defines what has to be displayed at the top of the screen. Has various properties like title,padding,brightness.

Body

It's the area below the Appbar and behind the buttons. Any widget in the body is positioned at the top left corner by default.

FloatingActionButton

Is a button displayed floating in the bottom right corner. We use this button to promote a primary action in the application.

Drawer

Is a panel displayed to the side of the body. One usually has to swipe left to right of right to left to access the drawer. It uses the Drawer properties which is a material design panel that slides from the edge of a Scaffold to show links in an application.

Signing in with Google using Flutter

After a lot of research I realized that the only way to log in to Google without using Firebase is through the packages provided by Google.
Using these packages we can make the user log in without saving their personal data, except the data we want to show , like email and username.

Flutter

Let's get started. First of all we have to create a new Flutter Project.
Choose the Flutter Application option.

Flutter

Insert the Name of the Project and the company name.
After that in the 'main.dart' remove all the code except the main and switch the (MyApp) to (MaterialApp).
Insert 'Title'.

Flutter

Create a new class to extend a 'StatefulWidget'.
Change return 'Container' to 'Scaffold' so we can use the features provided by the Scaffold Class.

Flutter

Enter in 'pubspec.yaml' , then go to google and search for google sign in package flutter or click this link: https://pub.dev/packages/google_sign_in, go to installing and add that command to 'pubspec dependecies'.

Flutter

Flutter

Click on "Packages get" as we made a change to the packages to update.

Flutter

Import the Google package to 'main.dart'.

Flutter

Create the 'GoogleSignIn' object, provide the scope profile and email to that object.

Flutter

You need to create a SignInAccount object.
Name that object 'user' to be used to see if he is signed in or signed out.

Inside the 'Scaffold' use the 'AppBar' to add a Title.

Flutter

In the 'body' create a method '_buildbody'.
Inside that method you need to add a 'ListTile' to display the information,then use a GoogleUserCircleAvatar to display the profile image.

Flutter

Make the title and subtitle show the 'Name' and 'Email' on the screen. Create a button to be pressed with the text 'Sign out'.

Flutter

Flutter

In short, if the user is not connected, a message appears saying "Not Signed in". If this user is already connected, his data is displayed and a button appears saying "Sign Out".

Now, create both _GetSignIn and _GetSignOut methods.
Use the method silently/ SignInSilently(); -> Used to Sign In the user without interaction.

Flutter

After the UI is completed we need to register the App in the Firebase.
Even if we don't need to use Firebase the App has to be registered there.

So go to: https://console.firebase.google.com/u/0/ In the Firebase console, add a new project and get the same package name from your app.

Flutter

You will need to get the SHA-1 so go to 'gradlew' and to the terminal and run the command- 'gradlew signinReport'.

Flutter

Flutter

Insert the SHA-1 in the Firebase space then, download the file and paste it inside the Android > app.

Follow the steps to add the Firebase SDK / Go to people API:

https://developers.google.com/people/v1/getting-started

Follow those 3 steps.

Flutter

After that go to credentials and click the user data option.
Click on the API and go for Android or IOS.
Name your app again, put the SHA-1 you got from 'gradlew' and the package name you can find in your 'AndroidManifest.xml'.

Flutter

Set up the consent screen, go to support email and select your email then click save.
Go to OAuth 2.0 Cliente IDs, select the Android option.

On your Manifest.xml add below the package name this line:

   <uses-permission android:name="android.permission.INTERNET"/>

Then just edit the button as you like and the Google login is fully functional.

How to use SQLite in Flutter

Flutter

Persisted data ( persitent Date ) are very important for users, since they would be inconvenient to always be writing your information or wait for the network carry the same data again. In these situations, it would be best to store your data locally.

Why SQLite?

SQLite is one of the most popular methods for storing data locally. For this article, we will use the package ( package ) sqflite acceded to SQLite. Sqflite is one of the most used and updated packages to connect to SQLite databases in Flutter.

How to use Sqflite on Flutter?

1. Add the dependency to the project

In our project, we will open the file pubspec.yaml and search for dependencies. Under dependencies we add the latest version of sqflite and path_provider(which can be removed from pub.dev).

 dependencies:
  flutter:
    sdk: flutter
  sqflite: any
  path_provider: any

2. Creating a DB Client

Now, in our project, we will create a new Database.dart file.

1- Creation of a private builder that can be used only within the class:

class DBProvider {
  DBProvider._();
  static final DBProvider db = DBProvider._();
}

2- Preparation of the database Next we will create the database object and provide you with a getter, which will create an instance of the database, if it has not already been created.

static Database _database;

  Future<Database> get database async {
    if (_database != null)
    return _database;

    // if _database is null we instantiate it
    _database = await initDB();
    return _database;
  }

If no objects are assigned to the database, we use the initDB function to create the database. In this function, we get the directory where we will store the database and create the tables we want:

initDB() async {
    Directory documentsDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentsDirectory.path, "TestDB.db");
    return await openDatabase(path, version: 1, onOpen: (db) {
    }, onCreate: (Database db, int version) async {
      await db.execute("CREATE TABLE Client ("
          "id INTEGER PRIMARY KEY,"
          "first_name TEXT,"
          "last_name TEXT,"
          "blocked BIT"
          ")");
    });
  }

3. Creation of Model Class

The data inside our database will be converted to Dart Maps, so first we need to create the Model Classes with the 'toMap' and 'fromMap' methods.

/// ClientModel.dart
import 'dart:convert';

Client clientFromJson(String str) {
  final jsonData = json.decode(str);
  return Client.fromMap(jsonData);
}

String clientToJson(Client data) {
  final dyn = data.toMap();
  return json.encode(dyn);
}

class Client {
  int id;
  String firstName;
  String lastName;
  bool blocked;

  Client({
    this.id,
    this.firstName,
    this.lastName,
    this.blocked,
  });

  factory Client.fromMap(Map<String, dynamic> json) => new Client(
        id: json["id"],
        firstName: json["first_name"],
        lastName: json["last_name"],
        blocked: json["blocked"] == 1,
      );

  Map<String, dynamic> toMap() => {
        "id": id,
        "first_name": firstName,
        "last_name": lastName,
        "blocked": blocked,
      };
}

4. CRUD Operations

Using 'Insert':

newClient(Client newClient) async {
    final db = await database;
    var res = await db.insert("Client", newClient.toMap());
    return res;
  }

Get Client via an ID:

getClient(int id) async {
    final db = await database;
    var res =await  db.query("Client", where: "id = ?", whereArgs: [id]);
    return res.isNotEmpty ? Client.fromMap(res.first) : Null ;
  }

Obtain all Clients with one condition: In this example, we use rawQuery to map the results list to a list of Client objects:

getAllClients() async {
    final db = await database;
    var res = await db.query("Client");
    List<Client> list =
        res.isNotEmpty ? res.map((c) => Client.fromMap(c)).toList() : [];
    return list;
  }

Update an existing Client:

updateClient(Client newClient) async {
    final db = await database;
    var res = await db.update("Client", newClient.toMap(),
        where: "id = ?", whereArgs: [newClient.id]);
    return res;
  }

Delete a Client:

deleteClient(int id) async {
    final db = await database;
    db.delete("Client", where: "id = ?", whereArgs: [id]);
  }

Delete All Clients:

deleteAll() async {
    final db = await database;
    db.rawDelete("Delete * from Client");
  }

Trouble-Shooting Section

The first time I tried to change the path of the Flutter folder so that it could be accessed by the terminal without having to use several paths, it did not work, every time I closed the terminal Flutter was no longer recognized.

command not found: flutter

Whenever I used this command:

export PATH="$PATH:~/development/flutter/bin

Then I started to notice that this command only worked for the current terminal, so it was not permanent. Even using the command that should change the path permanently Flutter was still unrecognized.

This would be the command that would make Flutter access through the terminal permanent:

export PATH="$PATH:[PATH_TO_FLUTTER_GIT_DIRECTORY]/flutter/bin"

Changing the path to where we would have cloned Flutter's Git repository [PATH_TO_FLUTTER_GIT_DIRECTORY]. And then using the command:

source ~/.bash_profile

What will help us refresh the terminal.
But even so, every time I closed and opened the terminal again Flutter was no longer recognized.
So I thought that maybe the best option would be to go to the document and edit it with the "export PATH" command but inside the document itself other than in the terminal.

So I went to Finder / Macintosh HD / Users / and to my user. How is a hidden file or document we must type cmd + shift + .

finder-view-showing-flutter-directory

Then I opened my .zhs_profile file and typed the command:

export PATH=/Users/m/Documents/flutter/bin:$PATH

This instructs my terminal environment to export an updated version of the PATH environment variable with flutter/bin path prepended to the current PATH variable. (i.e. add flutter/bin to the PATH so that my terminal knows where to find the flutter CLI)

Then I saved the file and now going to the terminal Flutter is already recognized and can be accessed without having to run any commands.

flutter-command-output-truncated

How can you improve your learning in Flutter?

  • Get to know the Flutter platform vividly
  • Thoroughly acquaint with all the features of Flutter
  • Read through Flutter’s official documentation as it include easy examples that beginners would find helpful. The documents are seasoned with iOS and Android devices. The developers can easily interact with the present device
  • Including Google codelabs in the learning process
  • Adding the Flutter GitHub repository in the learning process
  • Opting for Google’s free beginner Flutter learning course. Google provides a free course for learners.