Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
FLUTTER WITH VSC MOBILE PROGRAMMING
Ahmad Hanis Mohd Shabli 9/11/19 STIW2044
1
Table of Contents Introduction to Flutter ............................................................................................................................ 3
Why Flutter? ....................................................................................................................................... 3
Flutter Installation ................................................................................................................................... 4
Introduction ........................................................................................................................................ 4
Requirement ....................................................................................................................................... 4
Android Studio .................................................................................................................................... 4
XCode .................................................................................................................................................. 5
Visual Studio Code .............................................................................................................................. 5
Git ........................................................................................................................................................ 6
Flutter SDK .......................................................................................................................................... 6
Testing Flutter application .................................................................................................................. 7
Flutter Basic ............................................................................................................................................ 8
New Project ......................................................................................................................................... 8
Basic Layout ...................................................................................................................................... 12
Column Layout Widget ..................................................................................................................... 14
Text Widget ....................................................................................................................................... 15
TextField Widget ............................................................................................................................... 16
Button ............................................................................................................................................... 17
User Defined Widget ......................................................................................................................... 18
Simple Flutter Application .................................................................................................................... 21
Basic Input Output ............................................................................................................................ 21
Stateless vs Stateful Widget .......................................................................................................... 21
Simple Calculator .............................................................................................................................. 24
Widget Decoration (new widget!) ................................................................................................ 26
Assignment .................................................................................................................................... 28
BMI Calculator ................................................................................................................................... 28
Image Widget (new widget!) ........................................................................................................ 31
Pubspec.yaml ................................................................................................................................ 32
Play Audio (new widget!) .............................................................................................................. 34
Library ........................................................................................................................................... 34
Food Ninja ............................................................................................................................................. 39
Splash Screen .................................................................................................................................... 40
Debug Options .............................................................................................................................. 42
SizedBox (new widget!) ................................................................................................................. 43
LinearProgressIndicator Widget ................................................................................................... 43
2
Renaming main.dart to splashscreen.dart .................................................................................... 43
Login Screen ...................................................................................................................................... 45
Page Navigation ............................................................................................................................ 45
Handling Layout Overflow ............................................................................................................ 49
Padding option .............................................................................................................................. 49
Alignment option .......................................................................................................................... 50
SizedBox Widget ........................................................................................................................... 50
MaterialButton Widget ................................................................................................................. 50
GestureDetector Widget ............................................................................................................... 50
CheckBox Widget .......................................................................................................................... 51
Navigator Widget .......................................................................................................................... 51
Handling Preferences .................................................................................................................... 52
Register User ..................................................................................................................................... 54
User Registration Process ............................................................................................................. 59
Server Application Directory ......................................................................................................... 63
Database Connector...................................................................................................................... 64
3
Introduction to Flutter
Flutter is an open-source software development kit framework developed by Google to quickly build
IOS and Android mobile application with only single code base. Single code base allow developer to
develop application faster and cheaper. Flutter also compile code into native program that can run
much faster on IOS and Android. Flutter being supported by Google allow for wide variety of support
form the tech giant and also being open source in nature, with a lot of development communities
build sample application and libraries for Flutter.
Flutter use Dart programming language as its core programming code. Interface design and logic codes
can be combined into one Dart file. So far, Official Flutter dev didn’t release any GUI designer where
it allows for visual interface design using drag and drop feature something like what Android Studio
has provided. However, there are a number of online visual GUI design application available to
accelerate development.
Why Flutter?
There are a number of hybrid and cross platform mobile development platform such as Ionic, React,
React Native, Framework 7, and Xamarin. However, most of them are based on HTML technologies
where the application is wrap in a webview. Hybrid app needs native library to access to mobile
devices hardware such as sensors, camera, or other low-level hardware. Dependencies on these
libraries is quite difficult due to changes in mobile hardware is frequent. Webview wrapper also
produce bigger installation files compared to native application that produce small installation file.
These will lead to performance issue in hybrid application compared to native application. Read more
on hybrid vs native https://codeburst.io/native-app-or-hybrid-app-ca08e460df9.
The application written in flutter is compiled ahead-of-time into native ARM code, not at runtime as
in React Native. This gives better performance because there’s no JS bridge in the middle to parse and
execute the code.
Some big companies are already using it, such as Alibaba (Android, iOS), Tencent (Android, iOS), and
Google Ads (Android, iOS). Alibaba also used Flutter to build its Xianyu app (Android, iOS), currently
used by more than 50 million customers in China.
4
Flutter Installation
Introduction Preparing a fast and trouble-free development environment is important to avoid any delays in
developing a solution. The following guideline shows how prepare and install Flutter in a computer.
The installation process might change in the future due to new Flutter version.
Requirement Minimum requirement – i3 Intel based processor with 4GB of RAM. With this requirement, most of
the application and services to run Flutter run at very low performance. However, it is not
recommended to use this requirement. It is recommended to upgrade computers RAM to at least 8GB
with SSD main drive.
Recommended requirement – i5 and above processor with 8GB of RAM and SSD drive. It is suggested
to use this setup to help ease development process. Even though Visual Studio Code is considered as
non-intensive IDE, the other development components such as Android SDK and AVD demand
substantial amount of resources from computer. That can further reduce the performance of
computer due to limited resources available.
Android Studio Android studio is a development environment for developing mobile application for Android only
operating system. Even though the IDE itself it is not needed to during development process, the other
component provided by Android Studio such as AVD is needed to run Android virtual devices. AVD use
to test application develop using Flutter framework. Android Studio also can be used to develop
Flutter; however, it is not recommended due to high resource usage by Android Studio IDE that can
further reduce computer performance. Android Studio installer is available for Windows, MacOS and
Linux operating system.
5
Install Android studio with the latest SDK and tools using the recommended link suggested by official
Android Studio from the following website: https://developer.android.com/studio. Make sure to
Install and update SDK manager to the latest version of available SDK and tools. Download and create
new AVD to enable application testing on virtual device. Test newly created AVD to make sure it is
working as expected.
XCode XCode is development environment only available on MacOS computer. Please Install XCode to enable
IOS emulator.
Visual Studio Code Visual Studio Code is lightweight development IDE to be used with Flutter framework. The installer is
available on https://code.visualstudio.com for Window, MacOS and Linux operating system.
Download the required installer and perform installation according to guideline in the installer.
6
Git Git is a free and open source distributed version control system that allow user to download files
through terminal based application. Git is required to download Flutter SDK to local directory.
Download git from its official website: https://git-scm.com. The installer is available for Windows,
MacOS and Linux. Follow the Installation guide provided by the installer. Once the installation
completed, test the following git command through terminal. It should return current git version.
Flutter SDK Flutter SDK is available for download from https://flutter.dev/docs/get-started/install. Select the
operating system version that needed for the installation. The following guide is for Windows however
for other operating system, refers to online documentation available in official Flutter website. To
install Flutter SDK, create a new directory call flutter in drive C:\ (also can be in any other directory).
Then use command prompt terminal and access the directory. Do not install Flutter in a directory like
C:\Program Files\ that requires elevated privileges).
7
Next, download Flutter sdk using git clone command as follows:
git clone -b stable https://github.com/flutter/flutter.git
Update Flutter Environment
Update Flutter using Flutter Doctor
Install Flutter extensions to Visual Studio Code.
Testing Flutter application
on Android AVD/or IOS simulator.
8
Flutter Basic Creating new flutter project using Visual Studio Code is quite different then what available through
Android Studio or XCode. The following steps will describe how a new Flutter project can be created.
These processes might change in the future with new Flutter/Visual Studio Code release.
New Project Create new flutter project by selecting menu View/Command Palette and type “Flutter: New Project”
or press “Ctrl+Shift+P”.
Provide project name using only single words with all small letters.
Save the project into a workspace folder.
9
The following process may take a while due to VSC downloading all the required component from the
Internet. Wait for VSC to completely create project directory. This step requires Internet connection
(only require for every new project creation).
Once project have been successfully created, the following interface will be presented.
The default code provided by Flutter shows quite a lot of unnecessary code. To understand basic
Flutter programming structure, proceed to install Awesome Flutter Snippets by downloading from
Extensions Marketplace from Command Palette or press “Ctrl+Shift+X”. Search for Awesome Flutter
Snippets then download and install. Snippets make available a collection of ready-made code that can
be easily access from keywords type on a keyboard. Proceed with Awesome Flutter Snippets
installation (installation process will only require once).
10
Download and install the extension above then delete all the codes from default main.dart. Then
inside the main.dart workspace, press button “m” and select “mateapp” from the first popup menu
option and then press enter.
The following code will be automatically appear in main.dart. This is the most basic code structure for
Flutter Dart programming layout. It shows a simple layout screen with a text in the middle with Hello
World writing inside.
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Material App', home: Scaffold( appBar: AppBar( title: Text('Material App Bar'), ), body: Center( child: Container( child: Text('Hello World'), ), ), ), ); } }
11
The above code can be tested on AVD or IOS emulator. Press button F5 on Windows computer or
menu Debug/Start Debugging. Make sure at least one AVD is available. If no AVD available please
configure new AVD from Android Studio AVD manager. Application can also be tested using real device
by connecting the device to the development computer with development/debug mode enable. A
selection of device/avd will be presented with this option. Allow the device fingerprint debug mode.
Select the required testing platform and wait until the installation completed on device or AVD.
Once installation completed, the application will display a simple interface with a text in the middle
with “Hello World” text. On the right side, a bar display “DEBUG” shows the app is in debug mode.
Flutter allow fast development mode call “Hot Reload” that allow developer to modify their code and
quickly view their modified interface/code in an instant on the AVD or device. This handy feature is a
time saver where most of the time taken is when updated code need time to reinstall back on the
device on Android Studio or XCode.
Any new Flutter mobile application project will follow the above process except for installation of
Awesome Flutter Snippets plugin where it only needed once. Get use to these procedures for any
new Flutter project.
12
Basic Layout import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Material App', home: Scaffold( appBar: AppBar( title: Text('Material App Bar'), ), body: Center( child: Container( child: Text('Hello World'), ), ), ), ); } }
Flutter code like any other programming language start with statement to import required package
and for Flutter it is a mandatory library from ‘flutter/material.dart’. This package contains all basic
interface component/widget such as buttons, and text input which follow Android material design.
Next statement which is void main() method is the method that first initialized when application first
execute. Main method then called the class called MyApp() class to initialized and draw interface
based on defined widget.
Layout interface in flutter handle by a class and in above example define by MyApp() class that extend
to another parent class call Stateless Widget. Stateless widget is a component that do not store any
data (more on this later). Another type of layout widget is Statefull Widget that manage widget that
requires update to be redrawn back on the layout.
13
The overall structure of a widget is hold by Scaffold widget. Scaffold contain an AppBar (Application
Bar) and a Body that host all the interface widgets. Body of the layout set to center using Center
widget. Center widget contain one child Container and finally Container widget contain one Text
Widget. Container in this code hold the entire layout interface where text display in the middle of the
screen.
The above layout displays overall layout structure using basic Flutter code. However, no other
component can be added to the interface since widget container can only host one child widget. To
add more widget to the above layout such as button, image, and input text; continue with basic layout
management using column in the next section.
14
Column Layout Widget
Linear layout or column-based layout is the most basic layout for mobile interface. All widget
component can be arranged in column-based stack right on top of each other. To allow the above
awesome basic Flutter code snippet to accept multiple widget, a few modifications needed as follows.
Right click on body and choose Refactor menu.
Select Wrap with Column from menu option.
code will turn into the following:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Material App', home: Scaffold( appBar: AppBar( title: Text('Material App Bar'), ), body: Column( children: <Widget>[ Center( child: Container(
15
child: Text('Hello World'), ), ), ], ), ), ); } }
The Above code now will accept multiple Widget components such as button, text input and label.
This is due to the changes in body structure that accept row with multiple widget children’s using
arrays[].
children: <Widget>[ Center( child: Container( child: Text('Hello World'), ), ), ],
Text Widget Text widget is a simple widget that allow text to be drawn on the layout. To add text widget, simply
by adding the following Widget arrays.
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Material App', home: Scaffold( appBar: AppBar( title: Text('Material App Bar'), ), body: Column( children: <Widget>[ Text('Hello, How are you?'), Text('Welcome to Flutter'), Text('Develop with Visual Code Studio'), ],
16
), ), ); } }
There are three texts display in rows from the above example. Each on top of each other.
body: Column( children: <Widget>[ Text('Hello, How are you?'), Text('Welcome to Flutter'), Text('Develop with Visual Code Studio'), ], ),
There are more options that available to Text such as formatting, event handling, etc. For further
reference go to https://api.flutter.dev/flutter/widgets/Text-class.html.
TextField Widget
Text fields is another usefull widget that allow users to type text into an app. They are used to build
to get input from user. It is one of the most used widgets in mobile application interface.
children: <Widget>[ Container( child: Text('Email'), alignment: Alignment.centerLeft, ), TextField(), ],
Noted that a container has been used to control alignment for the Text above and set it to left
alignment. A simple widget call using TextField() allow the widget to appear on the layout.
17
More reference available from Flutter cookbook for TextField from the following link
https://flutter.dev/docs/cookbook/forms/text-input.
Button
Button is another interaction widget that allow user to click and perform task. There are a number of
button widget available for Flutter such as RaisedButton, FlatButton, Material Button, Floating
Button, and etc. To add button widget, simply insert RaisedButton with the following options inside
Widget array.
children: <Widget>[ Container( child: Text('Email'), alignment: Alignment.centerLeft, ), TextField(), RaisedButton( child: Text("Press Me"), onPressed: _pressMe, )
RaisedButton widget requires one child widget for label and one event method onPressed: that calls
_pressMe method. Add press_me method inside the class or click on the yellow lightbulb option to
quickly access method creation. Add a simple print statement to print on debug console a text.
void _pressMe() { print("Hello World"); }
18
User Defined Widget
“Everything in Flutter is a widget”. Understanding this concept is critical in order to fully recognized
the full potential of Flutter. User can define their own widget by combining several widgets together
or making their own custom widget. User defined widget allow for better grouping of similar widget
performing operation.
To create user defined widget, create a new project. Use “mateapp” plugin to create basic Application
interface. Then refactor Container with “Wrap with Column” to create Widget array. This will allow
layout to accept multiple widget. Remove the container from Widget array.
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Material App', home: Scaffold( appBar: AppBar( title: Text('Material App Bar'), ), body: Center( child: Column( children: <Widget>[], ), ), ), ); } }
19
Create another stateless class inside main.dart by press key s. A menu will appear after button s is
pressed. Select statelessW to automatically add a stateless class
Give the class name MyWidget and update with the following code
class MyWidget extends StatelessWidget { const MyWidget({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Container( child: Column( children: <Widget>[ Text('Hello from MyWidget'), Text('Welcome to MyWidget'), ], ), ); } }
Update MyApp class widget array with the three Text widgets as follows then run the project.
children: <Widget>[ Text('Hello from MyApp'), Text('Welcome to MyApp'), MyWidget(), ],
20
The project shows user defined widget with two Text widgets in MyWidget class. This shows the
grouping of multiple Widgets can be done using multiple classes (class can also be in different dart
file).
21
Simple Flutter Application
The following section will describe how to build simple application using just three basic widgets
introduced in the previous section. These applications will contain basic input, process and output.
Basic Input Output
The following application example will take input from input TextField and then when user press a
button, the value will be transferred to a Text. In this example a new state will be introduce called
StatefulWidget. This is due to when a widget needs to be able to accept dynamic new changes to its
content such as changes in the content display in a Text.
The following code is based on the previous topic that shows a simple interface with additional one
output text at the bottom.
children: <Widget>[ Container( child: Text('Email'), alignment: Alignment.centerLeft, ), TextField(), RaisedButton( child: Text("Press Me"), onPressed: _pressMe, ), Text("Output"), //new Text for output is here ],
Stateless vs Stateful Widget
The default class that contain this widget extends to StatelessWidget class. Stateless widget cannot
change its state and only suitable for widget that immutable (don’t change). These widgets such as
Text and icon don’t change most of the time and only need to be called once during build hence
suitable for StatelessWidget.
22
Stateless widget need to be refactored as StatefulWidget if the application needs widget to be able
to change its state. To refactor, right click on the class and select Refactor from the menu. Then select
Convert to StatefulWidget from the menu.
This option will automatically convert the widget into StatefulWidget class with class that extend to
State. The rest of the interface remain the same. StatefulWidget can change (redraw) their state many
times throughout the application lifecycle. Checkbox, Radio and TextField are some of the stateful
widgets.
class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override Widget build(BuildContext context) { .../
To get value from TextField, a controller and a variable needed to be defined inside _MyAppState
above. Add the following two instruction inside the class.
class _MyAppState extends State<MyApp> { final TextEditingController _emcontroller = TextEditingController(); String _email2 = "";
A controller allows for TextField to store its value and later access by another widget. Next step is to
update Widget array with the following:
children: <Widget>[ Container( child: Text('Email'), alignment: Alignment.centerLeft, ), TextField(controller: _emcontroller), RaisedButton( child: Text("Press Me"), onPressed: _onPressed,
23
), Text("Submitted Text: $_email2"), ],
The TextField widget define its controller as _emcontroller and any changes to its value will be stored
by this controller. The button implements onPressed with _onPressed method. This method should
be located inside the class MyAppState. This method contain setState method that perform the
setting of variable _email2 to the value of _emcontroller.
_onPressed() { setState(() { _email2 = _emcontroller.text; }); }
The last Text shows the value back to user by displaying the variable value when user click on the press
me button.
Full project code is as follows:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final TextEditingController _emcontroller = TextEditingController(); String _email2 = ""; @override Widget build(BuildContext context) {
24
return MaterialApp( title: 'Material App', home: Scaffold( appBar: AppBar( title: Text('Material App Bar'), ), body: Column( children: <Widget>[ Container( child: Text('Email'), alignment: Alignment.centerLeft, ), TextField(controller: _emcontroller), RaisedButton( child: Text("Press Me"), onPressed: _onPressed, ), Text("Submitted Text: $_email2"), ], ), ), ); } _onPressed() { setState(() { _email2 = _emcontroller.text; }); } }
Simple Calculator
Simple calculator takes two number from TextField and perform basic arithmetic operation such as
addition, subtraction, multiplication and division. Create new Flutter project call mycalculator. Clear
all the codes from default main.dart and import mateapp snippet. Then refactor StatelessWidget
class into StatefulWidget and also body into Wrap with Column. Finally remove the content of Widget
array.
Add two TextFields, a button and a Text as output on the layout. The following Widget arrays display
basic Widgets placement using its basic definition.
children: <Widget>[ TextField(), TextField(),
25
RaisedButton( child: Text("+"), onPressed: null, ), Text("Result:"), ],
The output from above code.
Full code for simple calculator.
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final TextEditingController _acontroller = TextEditingController(); final TextEditingController _bcontroller = TextEditingController(); double a = 0.0, b = 0.0, result = 0.0; @override Widget build(BuildContext context) { return MaterialApp( title: 'Material App', home: Scaffold( appBar: AppBar( title: Text('Material App Bar'), ), body: Column( children: <Widget>[ TextField(
26
controller: _acontroller, ), TextField( controller: _bcontroller, ), RaisedButton( child: Text("+"), onPressed: _onPress, ), Text("Result: $result"), ], ), ), ); } void _onPress() { setState(() { a = double.parse(_acontroller.text); b = double.parse(_bcontroller.text); result = a + b; }); } }
The application above shows basic calculator that able to perform simple addition operation.
Widget Decoration (new widget!)
However, the interface can be further improved by using several other Widgets. The following Scaffold
has been updated with additional widget.
home: Scaffold( resizeToAvoidBottomPadding: false, appBar: AppBar(
27
title: Text('Basic Calculator App'), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Padding( padding: EdgeInsets.fromLTRB(50, 0, 50, 0), child: TextField( decoration: InputDecoration( hintText: "First Number", ), keyboardType: TextInputType.numberWithOptions(), controller: _acontroller, ), ), Padding( padding: EdgeInsets.fromLTRB(50, 0, 50, 0), child: TextField( decoration: InputDecoration( hintText: "Second Number", ), keyboardType: TextInputType.numberWithOptions(), controller: _bcontroller, ), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Padding( padding: EdgeInsets.all(5), child: RaisedButton( child: Text("+"), onPressed: _onPress, ), ), Padding( padding: EdgeInsets.all(5), child: RaisedButton( child: Text("-"), onPressed: _onPress, ), ), ], ), Text("Result: $result"), ], ), ),
28
The interface has gone a lot of changes by including several widgets and options such as Padding and
InputDecoration, resizing and alignment. Noticed that new nested Row (red box) also has been used
in the Widget with new array Row allowing additional new button to the right. Padding also allow
Widget to move inwards and center making the interface look more accessible.
Assignment Complete the above simple calculator application with additional 3 arithmetic operations. Add two
more button below the “+” and “– “buttons. Each button must perform their own arithmetic
operation.
BMI Calculator
BMI calculator is another simple application that allow user to enter their weight and height and the
application will return BMI value back to user. Create new flutter project and insert two TextFields
and one Button and one Text as output. Use the previous example as guideline since the operation
more or less the same.
29
The application takes two input from user and then convert the value using BMI formula (height x
height) / Weight) Full code is available as follows:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final TextEditingController _acontroller = TextEditingController(); final TextEditingController _bcontroller = TextEditingController(); double a = 0.0, b = 0.0, result = 0.0; String bmi; @override Widget build(BuildContext context) { return MaterialApp( title: 'Material App', home: Scaffold( resizeToAvoidBottomPadding: false, appBar: AppBar( title: Text('BMI Calculator'), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Padding( padding: EdgeInsets.fromLTRB(50, 0, 50, 0), child: TextField( decoration: InputDecoration(
30
hintText: "Height(cm)", ), keyboardType: TextInputType.numberWithOptions(), controller: _acontroller, ), ), Padding( padding: EdgeInsets.fromLTRB(50, 0, 50, 0), child: TextField( decoration: InputDecoration( hintText: "Weight(kg)", ), keyboardType: TextInputType.numberWithOptions(), controller: _bcontroller, ), ), Padding( padding: EdgeInsets.all(5), child: RaisedButton( child: Text("Calculate BMI"), onPressed: _onPress, ), ), Text("BMI: $bmi"), ], ), ), ); } void _onPress() { setState(() { a = double.parse(_acontroller.text); b = double.parse(_bcontroller.text); result = (b * b) / a; bmi = format(result); }); } String format(double n) { return n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 2); } }
31
Image Widget (new widget!) Let’s add new Widget to the BMI application call image. Image allow user to show image from
application resources or from the Internet. Download the following file to drive
http://slumberjer.com/bmires.zip. Create a new folder call assets and sub folder inside assets call
images in the root of the project directory as follows.
Then right click on the images folder and select Reveal in Explorer menu or press Shift+Alt+R keys.
Unzip all the images and audio files into the folder.
The content of the images folder should appear inside the project explorer.
32
Pubspec.yaml
The next step is to register all images into the pubspec.yaml file under section assets. Pubspec is a file
within the project directory that responsible for project library import and assets management. More
on pubspec.yaml available here (https://flutter.dev/docs/development/packages-and-plugins/using-
packages ). Any new asset uses by Flutter project needed to be updated inside this file. For assets,
enable assets sections as follows.
# To add assets to your application, add an assets section, like this:
assets: - assets/images/
Then create a new variable call img under the widget class.
String img = "assets/images/default.jpg";
Add Image widget into widget array with in first column.
children: <Widget>[
Image.asset(img, height: 200.0, fit: BoxFit.cover), The application will display an image loaded from images directory using Image widget. Restart
application debug to take effect of the new assets. Static image will be displayed on the first column
of the application.
33
The following steps allow the application to change the image widget asset dynamically based on the
BMI value. When the BMI value is between certain ranges, image widget will be updated with different
image. Update the _onPress method with the following code:
void _onPress() { setState(() { a = double.parse(_acontroller.text); b = double.parse(_bcontroller.text); result = (b * b) / a; bmi = format(result); if (result > 25) { img = "images/overweight.jpg"; } else if ((result <= 24.9) && (result >= 18.5)) { img = "images/normal.jpg"; } else if (result < 18.5) { img = "images/underweight.jpg"; } }); } String format(double n) { return n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 2); }
Finally change Image widget as follows to set img variable defined above. Run the project.
new Image.asset(img, height: 200.0, fit: BoxFit.cover),
34
Run the project and test with different value. The image widget displays different images based on
the BMI value.
Play Audio (new widget!) Audio is an auditory clue that can be one of the features of an application. Event such as button click,
or result from processing can use audio as part of the user experience. Handling audio can be quite
challenging due to the way Android and IOS architecture of handling audio. Library audioplayers is
one of many libraries that can handle audio for Flutter.
The following application is an extension from BMI calculator. User result can trigger an audio cues to
show the perceptions of value such as producing trombone sound for overweight and underweight
result and success sound for normal BMI.
Library
Library is a preprogram code that can be used by a program. It is reusable code that make
programming easy and faster by including into a project. Flutter import library through pubspec.yaml
file. A section called dev_dependecies allow any online library to be directly downloaded and
imported into project. The name of the library is needed and included into pubspec.yaml. Be aware
with the tab indentation.
To use audioplayers library, access pubspec.yaml and update with the following dev_dependencies
section. Save and update the new dependencies.
dev_dependencies: flutter_test: sdk: flutter
35
audioplayers: ^0.13.1
Continue to create new folder call inside assets folder call audio and add the included two wav audio
files (fail.wav and ok.wav) into this folder. Save
Import the following libraries into the main.dart.
import 'package:audioplayers/audioplayers.dart'; import 'package:audioplayers/audio_cache.dart';
then continue to add the following two objects (audioCache and audioPlayer) inside the state class.
AudioCache audioCache = new AudioCache(); AudioPlayer audioPlayer = new AudioPlayer();
Insert two methods (loadOk and loadFail) inside the state class.
Future loadOk() async { audioPlayer = await AudioCache().play("audio/ok.wav"); } Future loadFail() async { audioPlayer = await AudioCache().play("audio/fail.wav"); }
and finally call this method from _onPress method.
if (result > 25) { img = "assets/images/overweight.jpg"; loadFail(); } else if ((result <= 24.9) && (result >= 18.5)) { img = "assets/images/normal.jpg"; loadOk(); } else if (result < 18.5) {
36
img = "assets/images/underweight.jpg"; loadFail(); }
Rerun the project on AVD and try one value for each three different BMI result. A short sound will be
played for each result.
The following is full project code for reference:
import 'package:flutter/material.dart'; import 'package:audioplayers/audioplayers.dart'; import 'package:audioplayers/audio_cache.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final TextEditingController _acontroller = TextEditingController(); final TextEditingController _bcontroller = TextEditingController(); double a = 0.0, b = 0.0, result = 0.0; String bmi; String img = "assets/images/default.jpg"; AudioCache audioCache = new AudioCache(); AudioPlayer audioPlayer = new AudioPlayer(); @override Widget build(BuildContext context) { return MaterialApp( title: 'Material App', home: Scaffold( resizeToAvoidBottomPadding: false, appBar: AppBar( title: Text('BMI Application'), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Image.asset(img, height: 200.0, fit: BoxFit.cover), Padding( padding: EdgeInsets.fromLTRB(50, 0, 50, 0), child: TextField( decoration: InputDecoration( hintText: "Height(cm)",
37
), keyboardType: TextInputType.numberWithOptions(), controller: _acontroller, ), ), Padding( padding: EdgeInsets.fromLTRB(50, 0, 50, 0), child: TextField( decoration: InputDecoration( hintText: "Weight(kg)", ), keyboardType: TextInputType.numberWithOptions(), controller: _bcontroller, ), ), Padding( padding: EdgeInsets.all(5), child: RaisedButton( child: Text("Calculate BMI"), onPressed: _onPress, ), ), Text("BMI: $bmi"), ], ), ), ); } void _onPress() { setState(() { a = double.parse(_acontroller.text); b = double.parse(_bcontroller.text); result = (b * b) / a; bmi = format(result); if (result > 25) { img = "assets/images/overweight.jpg"; loadFail(); } else if ((result <= 24.9) && (result >= 18.5)) { img = "assets/images/normal.jpg"; loadOk(); } else if (result < 18.5) { img = "assets/images/underweight.jpg"; loadFail(); } }); }
38
Future loadOk() async { audioPlayer = await AudioCache().play("audio/ok.wav"); } Future loadFail() async { audioPlayer = await AudioCache().play("audio/fail.wav"); } @override void dispose() { audioPlayer = null; super.dispose(); } String format(double n) { return n.toStringAsFixed(n.truncateToDouble() == n ? 0 : 2); } }
39
Food Ninja
In the previous topic, this book look into installation process, basic state and stateless widget layout
and with common layout Widgets such as Text, TextField, and RaisedButton. Simple layout manager
such as row and column widget have been used to manage widget placement on layout. Finally, Image
and audio widgets is use to allow application to provide visual and audio cue.
The following section will be based on a single application called FoodNinja. FoodNinja is an
application inspired by FoodPanda and GrabFood for online food delivery services. It is a complete
user side application that allow user to order food from participating local restaurants. User then can
pay online using online payment system and finally order can be delivered.
This application will serve as fundamental mobile application development stages with Flutter where
every step taken in developing this application will demonstrate certain topic that can be useful in
developing your complete application. The application starts from a splash screen where a form shows
a simple layout with a progress bar and a product logo. The screen then automatically moves to login
screen that allow user to login using email and password. User can also register using register layout.
Once successfully register, user can back to login and proceed to Main screen with listing of
participating restaurants. This application uses MySQL as its database and PhP as middleware.
Full source code is available from author Github page and will be used throughout this book as
reference if needed (https://github.com/ahmadhanis/FlutterWS/tree/master/food_ninja ). Some of
the code might be too long to put into this book, please refer to the link above for complete code.
Use the following YouTube tutorial how to clone github project to your computer
(https://www.youtube.com/watch?v=2Pi6ZKSbCp8).
40
Splash Screen
Splash screen is a simple screen with or without loading bar and a brand logo. This screen is normally
being use as product branding and only appear 2-3 seconds. It also provides first impression for user
how the overall look and feel of application.
Create new project called food_ninja in you VSC and proceed with the basic application structure
using mateapp plugin shortcut. Create a folder called /assets/images in Flutter project directory and
register the asset directory into pubspec.yaml. Download foodninja.png from
http://slumberjer.com/foodninja/images/foodninjared.png and copy into /assets/images directory.
Refactor container into column from basic mateapp code add two widgets into widget array.
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( theme: new ThemeData( primarySwatch: Colors.red), debugShowCheckedModeBanner: false, home: Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Image.asset( 'assets/images/foodninjared.png', width: 230, height: 230, ), SizedBox( height: 20, ), new ProgressIndicator(), ], ), ), ), ); } }
41
Pubspec.yaml assets section update.
# To add assets to your application, add an assets section, like this: assets: - assets/images/
Create a new Statefull class for ProgressIndicator() in the main.dart using stl shortcut as follows and
set the name of the class as ProgressIndicator.
Update ProgressIndicator class with the following code:
class ProgressIndicator extends StatefulWidget { @override _ProgressIndicatorState createState() => new _ProgressIndicatorState(); } class _ProgressIndicatorState extends State<ProgressIndicator> with SingleTickerProviderStateMixin { AnimationController controller; Animation<double> animation; @override void initState() { super.initState(); controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this); animation = Tween(begin: 0.0, end: 1.0).animate(controller) ..addListener(() { setState(() { //updating states if (animation.value > 0.99) { //Navigator.pushReplacement( // context, // MaterialPageRoute( // builder: (BuildContext context) => LoginPage())); } }); }); controller.repeat();
42
} @override void dispose() { controller.stop(); super.dispose(); } @override Widget build(BuildContext context) { return new Center( child: new Container( width: 200, color: Colors.redAccent, child: LinearProgressIndicator( value: animation.value, backgroundColor: Colors.black, valueColor: new AlwaysStoppedAnimation<Color>(Colors.red), ), )); } }
Run the project on AVD. The layout should show as follows.
Debug Options
There are a few new options introduced in this code. Under MaterialApp widget,
debugShowCheckedModeBanner is set to false where the debug banner is removed.
return MaterialApp(
43
debugShowCheckedModeBanner: false,
SizedBox (new widget!)
SizedBox is a widget a box drawn on the layout with a specific size. It is useful widget in managing
position of another widget or it can be parent to another widget for managing the widget size. More
on SizedBox from https://api.flutter.dev/flutter/widgets/SizedBox-class.html.
LinearProgressIndicator Widget
Progress indicator controller and animation is needed for the progress bar to show its progress value.
AnimationController controller; Animation<double> animation;
LinearProgressIndicator widgets is define in ProgressIndicator class in a container. A few other
parametes is set such as animation value and background color.
child: LinearProgressIndicator( value: animation.value, backgroundColor: Colors.black, valueColor: new AlwaysStoppedAnimation<Color>(Colors.red), ),
AnimationController set the duration of the animation for the splash screen to 2000ms (2 seconds).
Tween class is use to set animation range between 0.0 to 1.0 (0-100 percent).
controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this); animation = Tween(begin: 0.0, end: 1.0).animate(controller)
Renaming main.dart to splashscreen.dart
File main.dart is the default file name when new Flutter project is created. Since this is the default
debug configuration, to change this file name into another name requires a few configuration changes.
First, start with renaming the file from main.dart to splashscreen.dart by right right click and choose
rename. Then open launch.json file under .vscode folder or through Debug/Open Configurations
menu.
44
Change launch.json configuration as follows:
{ "name": "Flutter", "type": "dart", "request": "launch", "program": "lib/splashscreen.dart" }
Then open widget_test.dart under test folder and update library from main.dart to
splashscreen.dart. Save all the updated files and rebuild the project.
import 'package:food_ninja/splashscreen.dart';
For better understanding open the following link for full splashscreen.dart available at
https://github.com/ahmadhanis/FlutterWS/blob/master/food_ninja/lib/splashscreen.dart.
45
Login Screen
Most of online database type application will require a login page. Login page allow the application to
store and access user profile when using the application. But first the layout need to navigate from
splashscreen.dart (rename from main.dart) to new layout for loginpage.dart.
Page Navigation
Create new file in the lib folder call loginpage.dart. User “mateapp” to include base code for a layout.
Go back to splashscreen.dart and update the following code:
if (animation.value > 0.9) { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => LoginPage())); }
Navigator Widget with MaterialPageRoute allow current layout context to move from one layout to
the other. LoginPage() is the name of the class in loginpage.dart which handle login information.
and then remove everything inside MaterialApp widget. Update MaterialApp with the following code:
return new MaterialApp( title: 'Login', theme: new ThemeData(primarySwatch: Colors.red), home: new LoginPage(), );
Then create a statefull widget using “stl” shortcut text and name the class LoginPage. Create Scaffold
widget with Container for its body. Create child Column with widget array to host all other 3 widgets.
Full LoginPage class is as follows:
class LoginPage extends StatefulWidget { @override _LoginPageState createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { @override Widget build(BuildContext context) { return new Scaffold( body: new Container( child: Column( children: <Widget>[ Image.asset(
46
'assets/images/foodninjared.png', width: 150, height: 150, ), TextField( decoration: InputDecoration( labelText: 'Email', )), TextField( decoration: InputDecoration( labelText: 'Password', ), obscureText: true, ), RaisedButton(child: Text("login"),onPressed: null,) ], ), ), ); } }
The following layout is outcome from loginpage.dart class above.
Login shows product image with two TextFields with text input decoration email and password.
However, the positioning of all the widgets is quite off for example TextField needs padding to left
and right section, location of all the widgets should be in the middle of the screen and button doesn’t
seems suitable with overall design for the application. Update the class above with the following code:
47
import 'package:flutter/material.dart'; bool _isChecked = true; final TextEditingController _emcontroller = TextEditingController(); String _email = ""; final TextEditingController _pscontroller = TextEditingController(); String _pass = ""; class LoginPage extends StatefulWidget { @override _LoginPageState createState() => _LoginPageState(); } class _LoginPageState extends State<LoginPage> { @override Widget build(BuildContext context) { return new Scaffold( resizeToAvoidBottomPadding: false, body: new Container( padding: EdgeInsets.all(30.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Image.asset( 'assets/images/foodninjared.png', scale: 2.5, ), TextField( controller: _emcontroller, decoration: InputDecoration( labelText: 'Email', )), TextField( controller: _pscontroller, decoration: InputDecoration( labelText: 'Password', ), obscureText: true, ), Row( children: <Widget>[ Checkbox( value: _isChecked, onChanged: (bool value) { _onChange(value); }, ), Text('Remember Me', style: TextStyle(fontSize: 16))
48
], ), SizedBox( height: 10, ), MaterialButton( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20.0)), minWidth: 300, height: 50, child: Text('Login'), color: Color.black, textColor: Colors.white, elevation: 20, onPressed: _onPress, ), SizedBox( height: 20, ), Text("Register new account"), SizedBox( height: 10, ), Text('Forgot password') ], ), ), ); } void _onPress() { print(_emcontroller.text); print(_pscontroller.text); } void _onChange(bool value) { setState(() { _isChecked = value; print('Check value $value'); }); } }
The above update produces the following login page. It transforms the application with better look
and feels through widget positioning and sizing.
49
There are a number of new widgets and properties updated in the above code (check on the new
comment).
Handling Layout Overflow
Overflow widget displayed as black yellow marker that shows the UI widget element overflow the
overall display pixels. It is a common problem in Flutter interface design. To avoid this problem, use
option resizeToAvoidBottomPadding set to false added to scaffold.
resizeToAvoidBottomPadding: false,
Padding option
Padding allow for widget to have padding. Padding is an empty cushion surrounding a widget. Padding
use below set 30 pixels edge in all directions of the selected container.
padding: EdgeInsets.all(30.0),
50
Alignment option
Alignment option available for certain widget allow for widget to set its alignment to multiple types
such as center, start, and end.
mainAxisAlignment: MainAxisAlignment.center,
SizedBox Widget
SizedBox is a great widget for managing space in a layout or controlling other widget positioning and
sizing. The above code use SizedBox for managing spacing between password and login button at
the bottom.
SizedBox( height: 10, ),
MaterialButton Widget
Material button is just another type of button widget that allow widget to be resized using minWidth
option.
MaterialButton( minWidth: 300, child: Text('Login'), color: Colors.black, textColor: Colors.white, elevation: 15, onPressed: _onPress, ),
There are a number of other options available that follows material design concept from Android.
Explore more option using flutter cookbook (https://flutter.dev/docs/cookbook).
GestureDetector Widget
Gesture detector is a widget that allow the application to detect any gesture from user. It enables any
widget to implement action such as onTap enabling the widget to call certain method. Set the widget
that need gesture as a child to GestureDetector and automatically the widget can implement
interactivity.
GestureDetector( onTap: _onRegister, child: Text('Register New Account',
51
style: TextStyle(fontSize: 16))),
CheckBox Widget
CheckBox widget use in the login screen to store user credential in the application preference. This
give option not to type in their credential every time using the application. CheckBox widget in the
code is wrap in a Row widget with widget array to allow row positioning of checkbox and textbox in a
single row. Then isChecked method is used to allow checked operation
Row( children: <Widget>[ Checkbox( value: _isChecked, onChanged: (bool value) { _onChange(value); }, ), Text('Remember Me',style: TextStyle(fontSize: 16)) ], ),
Navigator Widget
Before user can proceed with login operation, they first need to register their account using
registration layout. Create new file call registeruser.dart and add “mateapp” script to the file. Update
onRegister method from loginpage.dart with Navigator widget to navigate to a new page call
registeruser.dart. Navigator widget allow layout to navigate from one to the other by calling the class
name.
void _onRegister() { Navigator.push( context, MaterialPageRoute(builder: (context) => RegisterUser())); }
import 'package:food_ninja/registeruser.dart';
Remember to import package registeruser.dart in the import section. Named route is another option
that can be used to navigate around layouts.
52
Handling Preferences Preferences is a simple paired data stored in a file application directory. It uses to store simple
preference data such as settings, username or password. Application can load from preference and
use the data. The following async method is use to save email and password data in preference. When
user press checkbox to store their username and password, prefs object store using setString method.
void savepref(bool value) async { print('Inside savepref'); _email = _emcontroller.text; _pass = _pscontroller.text; SharedPreferences prefs = await SharedPreferences.getInstance(); if (value) { //true save pref if (_isEmailValid(_email) || _pass.length < 5) { await prefs.setString('email', _email); await prefs.setString('pass', _pass); print('Save pref $_email'); print('Save pref $_pass'); Toast.show("Preferences saved succesfully", context, duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM); } else { print('No email'); setState(() { _isChecked = false; }); Toast.show("Invalid Preferences", context, duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM); } } else { await prefs.setString('email', ''); await prefs.setString('pass', ''); setState(() { _emcontroller.text = ''; _pscontroller.text = ''; _isChecked = false; }); print('Remove pref'); Toast.show("Preferences removed", context, duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM); } }
The other part of preference is to load data back into application. The following method loadpref()
handle load data from pref object.
53
void loadpref() async { print('Inside loadpref()'); SharedPreferences prefs = await SharedPreferences.getInstance(); _email = (prefs.getString('email')); _pass = (prefs.getString('pass')); print(_email); print(_pass); if (_email.length > 1) { _emcontroller.text = _email; _pscontroller.text = _pass; setState(() { _isChecked = true; }); } else { print('No pref'); setState(() { _isChecked = false; }); } }
To load preference, call the method from initState override method. This method load everytime the
login page loaded.
@override void initState() { loadpref(); print('Init: $_email'); super.initState(); }
Full code for login screen implemented by loginpage.dart is available from the following github link (
https://github.com/ahmadhanis/FlutterWS/blob/master/food_ninja/lib/loginpage.dart).
Don’t forget to update pubspec.yml for dependencies required.
https://github.com/ahmadhanis/FlutterWS/blob/master/food_ninja/pubspec.yaml
54
Register User
Registration page allow user to register their account. This page is call from login page where new user
is required to create new account. The following code use statefull widget for registration page. There
are 5 inputs required from user; an image, name, email, password and phone number.
import 'dart:io'; import 'package:flutter/material.dart'; import 'dart:async'; import 'package:flutter/services.dart'; import 'loginpage.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:image_picker/image_picker.dart'; import 'package:toast/toast.dart'; import 'package:progress_dialog/progress_dialog.dart'; String pathAsset = 'assets/images/profile.png'; File _image; String urlUpload = "http://slumberjer.com/foodninja/php/register_user.php"; final TextEditingController _namecontroller = TextEditingController(); final TextEditingController _emcontroller = TextEditingController(); final TextEditingController _passcontroller = TextEditingController(); final TextEditingController _phcontroller = TextEditingController(); String _email, _password, _phone,_name; class RegisterUser extends StatefulWidget { @override _RegisterUserState createState() => _RegisterUserState(); const RegisterUser({Key key, File image}) : super(key: key); } class _RegisterUserState extends State<RegisterUser> { @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return WillPopScope( onWillPop: _onBackPressAppBar, child: Scaffold( resizeToAvoidBottomPadding: false,
55
appBar: AppBar( title: Text('New User Registration'), backgroundColor: Colors.black, ), body: SingleChildScrollView( child: Container( padding: EdgeInsets.fromLTRB(40, 20, 40, 20), child: RegisterWidget(), ), ), ), ); } Future<bool> _onBackPressAppBar() async { _image = null; Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => LoginPage(), )); return Future.value(false); } } class RegisterWidget extends StatefulWidget { @override _RegisterWidgetState createState() => _RegisterWidgetState(); } class _RegisterWidgetState extends State<RegisterWidget> { @override Widget build(BuildContext context) { return Column( children: <Widget>[ GestureDetector( onTap: _choose, child: Container( width: 180, height: 200, decoration: BoxDecoration( shape: BoxShape.circle, image: DecorationImage( image: _image == null ? AssetImage(pathAsset) : FileImage(_image), fit: BoxFit.fill, )),
56
)), Text('Click on the image above to take profile picture'), TextField( controller: _namecontroller, keyboardType: TextInputType.text, decoration: InputDecoration( labelText: 'Name', icon: Icon(Icons.person), )), TextField( controller: _emcontroller, keyboardType: TextInputType.emailAddress, decoration: InputDecoration( labelText: 'Email', icon: Icon(Icons.email), )), TextField( controller: _passcontroller, decoration: InputDecoration(labelText: 'Password', icon: Icon(Icons.lock)), obscureText: true, ), TextField( controller: _phcontroller, keyboardType: TextInputType.phone, decoration: InputDecoration(labelText: 'Phone', icon: Icon(Icons.phone))), SizedBox( height: 10, ), MaterialButton( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)), minWidth: 300, height: 50, child: Text('Register'), color: Colors.black, textColor: Colors.white, elevation: 15, onPressed: _onRegister, ), SizedBox( height: 10, ),
57
GestureDetector( onTap: _onBackPress, child: Text('Already Register', style: TextStyle(fontSize: 16))), ], ); } void _choose() async { _image = await ImagePicker.pickImage(source: ImageSource.camera); setState(() {}); // file = await ImagePicker.pickImage(source: ImageSource.gallery); } void _onRegister() { print('onRegister Button from RegisterUser()'); print(_image.toString()); uploadData(); } void _onBackPress() { _image = null; print('onBackpress from RegisterUser'); Navigator.pushReplacement(context, MaterialPageRoute(builder: (BuildContext context) => LoginPage())); } void uploadData() { ProgressDialog pr = new ProgressDialog(context,type: ProgressDialogType.Normal, isDismissible: false); pr.show(); _name = _namecontroller.text; _email = _emcontroller.text; _password = _passcontroller.text; _phone = _phcontroller.text; print(_image); if ((_image == null) || (!_isEmailValid(_email)) || (_password.length < 5) || (_phone.length < 5)) { Toast.show("Invalid Registration Data", context, duration: Toast.LENGTH_SHORT, gravity: Toast.BOTTOM); return; } String base64Image = base64Encode(_image.readAsBytesSync()); http.post(urlUpload, body: {
58
"encoded_string": base64Image, "name": _name, "email": _email, "password": _password, "phone": _phone, }).then((res) { print(res.statusCode); print(res.body); _image = null; _namecontroller.text=''; _emcontroller.text = ''; _phcontroller.text = ''; _passcontroller.text = ''; Toast.show(res.body, context, duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM); Navigator.pushReplacement(context, MaterialPageRoute(builder: (BuildContext context) => LoginPage())); }).catchError((err) { print(err); }); pr.dismiss(); } bool _isEmailValid(String email) { return RegExp(r"^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+").hasMatch(email); } }
RegisterUser widget above wrap all body layout into SingleChildScrollView widget where it allow for
the layout to be scrollable if run on smaller screen. The register screen contain four textfield widgets,
a text widget, a button widget and an image widget respectively for name, email, password, phone,
profile image and text return link. Four controllers attached to each of the textfield. Image widget
surrounded with gesture detector widget to enable on tap operation. When user click on the image,
_choose method is call and imagepicker object initiated to run camera. User are required to capture
image and insert data all data into textfields. Image for profile.png image can be downloaded from
from http://slumberjer.com/foodninja/images/profile.png add then add into assets/images folder.
The next step will require backend processing to upload profile image into server directory and Mysql
database to store all user information. FoodNinja uses PhP as backend script to manage operation
between mobile application and database.
59
Reinstall the application on AVD test the application layout flows with new plugin. Comment if any
of the code above shows error at this stage.
User Registration Process Image and user data from above need to be stored in an online storage. For this step, a web hosting
is needed. You can use local web hosting by installing XAMPP or WAMP application. However, it is
recommended to purchase your own domain. This can benefit in the long run where the application
can be run anywhere.
Create Database The first step is to create MySQL database. Login to cpanel and access MySQL Database Wizard.
60
Give the database a name and press next step button.
Then create user admin for the database. Set username and password and make sure to keep this
information. Choose strong password using auto generated password.
Next step is to add user admin to the database. Select all privileges for the user admin.
61
Database creation completed. Make sure to store all the required information later needed for
database connector in PhP as follows:
DB name: slumber6_myhelper DB pass: xxxxxxxxxxxx (your password) DB user: slumber6_myhelperadmin Server: Localhost
Table creation Once database successfully created, the next step from here is to create table to store data. Back to
main CPanel menu and access phpMyAdmin page. Select the database name from the list.
Create table USER with 5 columns.
62
Set 5 fields as follows:
And finally press create table.
To test if the table can be used to insert data, access SQL tab and enter the following SQL query.
INSERT INTO `USER`(`NAME`, `EMAIL`, `PASSWORD`, `PHONE`) VALUES
('hanis','[email protected]','12312334234324325','01944556554')
63
Server Application Directory
Once database is ready, the next step is to start preparing for PhP database connector. However,
before that an application directory is needed to store all PhP files or any other files for the application.
Open File Manager from CPanel main menu and access to public_html folder. This folder is the root
of a web server.
Create a folder call foodninja in public_html folder. This folder can be access using web URL
htt://slumberjer.com/foodninja. Disable directory browsing for added security or better enable SSL
for the web server. As for now, use default setting. Create three folders images, php and profile inside
foodninja directory. Images will store any images uses by the application, php store all php files and
profile for user image profile.
64
Database Connector
Database connector is a php file use as establishing database connection. It contains information on
server name, username, password and database name. Create a new file call dbconnect.php in folder
PHP. Copy the following code into this folder and save. Make sure to change your dbname, password
and username accordingly.
<?php $servername = "localhost"; $username = "slumber6_adminfoodninja"; $password = "dG2=KVSSxyRm"; $dbname = "slumber6_foodninja"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } ?>