A new Flutter project demonstrating data fetchig from worldtimeAPI and displaying the time.
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.
For installing flutter to your operating system, follow the installation procedure.
Open VS code and in the terminal run the following command to create a flutter application.
flutter create <name_of_application(in_lower_case)>
After the flutter applciation is created the folder structure should look like something below.
world_time_app
├── .dart_tool
| └── ...
├── .idea
| └── ...
├── android
| └── ...
├── build
| └── ...
├── ios
| └── ...
├── lib
| └── main.dart
├── test
| └── ...
├── web
| └── ...
├── .gitignore
├── .metadata
├── .packages
├── pubspec.lock
├── pubspec.yaml
├── Readme.md
└── world_time_app.iml
-
.idea: This folder is at the very top of the project structure, which holds the configuration for Android Studio.
-
android: This folder holds a complete Android project and used when you build the Flutter application for Android. When the Flutter code is compiled into the native code, it will get injected into this Android project, so that the result is a native Android application.
-
ios: This folder holds a complete Mac project and used when you build the Flutter application for iOS. It is similar to the android folder that is used when developing an app for Android. When the Flutter code is compiled into the native code, it will get injected into this iOS project, so that the result is a native iOS application.
-
lib: It is an essential folder, which stands for the library. It is a folder where we will do our 99 percent of project work. Inside the lib folder, we will find the Dart files which contain the code of our Flutter application. By default, this folder contains the file main.dart, which is the entry file of the Flutter application.
-
test: This folder contains a Dart code, which is written for the Flutter application to perform the automated test when building the app. It won't be too important for us here.
-
.gitignore: It is a text file containing a list of files, file extensions, and folders that tells Git which files should be ignored in a project. Git is a version-control file for tracking changes in source code during software development Git.
-
.metadata: It is an auto-generated file by the flutter tools, which is used to track the properties of the Flutter project. This file performs the internal tasks, so you do not need to edit the content manually at any time.
-
.packages: It is an auto-generated file by the Flutter SDK, which is used to contain a list of dependencies for your Flutter project.
-
pubspec.yaml: It is the project's configuration file that will use a lot during working with the Flutter project. It allows you how your application works. This file contains:
- Project general settings such as name, description, and version of the project.
- Project dependencies.
- Project assets (e.g., images).
-
pubspec.lock: It is an auto-generated file based on the .yaml file. It holds more detail setup about all dependencies.
-
README.md: It is an auto-generated file that holds information about the project. We can edit this file if we want to share information with the developers.
-
world_time_app.iml: It is always named according to the Flutter project's name that contains additional settings of the project. This file performs the internal tasks, which is managed by the Flutter SDK, so you do not need to edit the content manually at any time.
The test folder can be deleted from the project directory, since its of no use for now.
In our application we shall be having the following :
- Four widgets
- Initial Loading Page [ Will show when data is fetched from API ]
- Home Page [ Will display the response from API ]
- Select Location [ Will display a list view of all the timezones ]
- Error [ This widget shall pop when any kind of exception/error/network connection issue occured]
- One Service
- Will be having the functions for request and response handling from worldtime API
Create a two directories inside lib
folder, namely
- pages
- services
Inside services
directory create a folder namely services.dart
.
This file shall be dealing with request and response handling from the worldtimeapi.
In the services.dart
file we shall be requiring http
and intl
for request/response and datetime format functions respectively.
And, since these dependencies are not by deafult included while creating the project we need to add the dependencies manually.
Get the latest version of http and intl and add to pubspec.yaml
file. After adding the dependencies the file should look as below.
dependencies:
flutter:
sdk: flutter
http: ^0.13.3
intl: ^0.17.0
If the dart plugin is already installed in VScode it would automatically run the flutter pub get
code else manually run the code in the terminal to install the packages.
import 'package:http/http.dart'; //deals with request/response functions
import 'dart:convert';
import 'package:intl/intl.dart';
In the below code snipped a WorldTimeData class is created and the variables are defined. The class has a constructor to enable it have parameters. The class has an asynchronous function timeData()
which has been enabled with try cath
functionality. If any exception occurs then isError variable is assigned true so that the error widget would pe pushed.
class WorldTimeData{
String url;
String time;
String location;
bool isDay;
bool isError;
WorldTimeData({this.url, this.location});
Future<void> timeData() async {
try {
var url_time = Uri.https("worldtimeapi.org", "/api/timezone/$url");
Response response =
await get(url_time);
Map data = jsonDecode(response.body);
String offset_hour = data['utc_offset'].substring(1, 3);
String offset_minute = data['utc_offset'].substring(4, 6);
DateTime now = DateTime.parse(data['datetime']);
now = now.add(Duration(hours: int.parse(offset_hour), minutes: int.parse(offset_minute)));
time = DateFormat.jm().format(now);
isDay = now.hour >= 6 && now.hour < 18 ? true : false;
}
catch(e){
isError = true;
print("Error in loading $e");
}
}
}
-
In the
try{}
segment a https request is made to worldtimeapi and the response is recordedresponse
variable. In thecatch(e){}
the exception is printed andisError
flag is assigned a true value. -
The documentation for Uri.https is in here. It's preferred to use Uri.https rather than Uri.http since it connetion is secure and the debugger won't raise issues regarding insecure connection.
Lets say one want to make a https request to http://worldtimeapi.org/api/timezone/Africa/Abidjan. The code would be as below
Uri.https("worldtimeapi.org", "/api/timezone/Africa/Abidjan"); //defines the url to which the request would be sent Response response = await get(url_time); //initiates a request and waits for the response and stores in response variable
Since the function of asynchronous, the
await
keyword ensures that the programs waits for the response from the API and then the further lines are executed. -
The Json data from the API is stored in response varible in the body key in String format. Since, the
String
format is not much interpretanle we converted it into Map format using the following code and store indata
variableMap data = jsonDecode(response.body)
-
Now individual information can be extracted by accessing different keys in the data Map variable.
Furthermore certain indiviual information are stored into String Variable by the accessing the keys of
Map data
String offset_hour = data['utc_offset'].substring(1, 3); //for the hours value of the offsets String offset_minute = data['utc_offset'].substring(4, 6); //for getting the minutes value of the offset
-
The current time is parsed to DateTime format by the following code
DateTime now = DateTime.parse(data['datetime']);
-
In order to get the actual time at different location as per GMT values of different timezones, it is added to the
now
variable via the following codenow = now.add(Duration(hours: int.parse(offset_hour), minutes: int.parse(offset_minute)));
-
To display a proper timeformat we use the
DateFormat.jm().format(<variable>)
ofintl
packagetime = DateFormat.jm().format(now);
-
isDay
is boolean variable which notifies whether the time hours comes under daylight hours or not.isDay = now.hour >= 6 && now.hour < 18 ? true : false;
The code snippet below is used to request for timezone from worldtimeapi and convert the response into list of timezones.
class LocationData{
List lData;
bool isError;
Future<void> locationData() async{
try{
var url_timezone = Uri.https("worldtimeapi.org", "/api/timezone");
Response locationData = await get(url_timezone);
lData = json.decode(locationData.body);
}
catch(e){
print("Error in locationData $e");
isError = true;
}
}
}
-
Initially the variables are defined and then a future asynchronous
locationData()
function is defined withtry catch
functionality. -
The url for requesting timezone is http://worldtimeapi.org/api/timezone/, which is defined via the following command
var url_timezone = Uri.https("worldtimeapi.org", "/api/timezone");
-
The request is initiated and the response is stored via the following code.
Response locationData = await get(url_timezone);
-
The conversion of the response into list format and stored in
lData
using the followinglData = json.decode(locationData.body);
And now since all our service function are created, let's start creating our main widgets.
Inside the pages
direcotry create 4 dart files namely,
- error.dart
- home.dart
- loading .dart
- location.dart
Copy paste the following code to error.dart, home.dart, loading.dart, location.dart
files.
import 'package:flutter/material.dart';
For the very initial create a stateful widget in all the files having widget name as Error, Home, Loading and Location
in the error.dart, home.dart, loading.dart and location.dart
respectively.
So respective files should look like this in the initial state
world_time_app/lib/pages/error.dart
import 'package:flutter/material.dart';
class Error extends StatefulWidget {
@override
_ErrorState createState() => _ErrorState();
}
class _ErrorState extends State<Error> {
@override
Widget build(BuildContext context) {
return Scaffold();
}
}
world_time_app/lib/pages/home.dart
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
return Scaffold();
}
}
world_time_app/lib/pages/loading.dart
import 'package:flutter/material.dart';
class Loading extends StatefulWidget {
@override
_LoadingState createState() => _LoadingState();
}
class _LoadingState extends State<Loading> {
@override
Widget build(BuildContext context) {
return Scaffold();
}
}
world_time_app/lib/pages/location.dart
import 'package:flutter/material.dart';
class Location extends StatefulWidget {
@override
_LocationState createState() => _LocationState();
}
class _LocationState extends State<Location> {
@override
Widget build(BuildContext context) {
return Scaffold(
);
}
}
Inside the lib folder, open the main.dart file in the editor. By default, it consists of some code. Delete everything present in main.dart and write the following code.
import 'package:flutter/material.dart';
import 'package:world_time_app/pages/home.dart';
import 'package:world_time_app/pages/loading.dart';
import 'package:world_time_app/pages/location.dart';
import 'package:world_time_app/pages/error.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
routes: {
"/": (context) => Loading(),
"/home": (context) => Home(),
"/location": (context) => Location(),
"/error" : (context) => Error(),
'/update' : (context) => UpdateTime()
},
));
}
-
import 'package:flutter/material.dart'; //imports all Material widgets import 'package:world_time_app/pages/home.dart'; //imports the Home() stateful widget import 'package:world_time_app/pages/loading.dart';//imports the Loading() and UpdateTime() stateful widget import 'package:world_time_app/pages/location.dart';//imports the Location() stateful widget import 'package:world_time_app/pages/error.dart';//imports the Error() stateful widget
-
This function consists of runApp function which ultimately results in the display of the application. We have used routes. THe default route is
"/"
. The function attached to the route shall be executed when the application is opened.debugShowCheckedModeBanner: false,
is mentioned so that thedebug
card that appears in the top-right corner of the application gets removed.