You are on page 1of 45

TRƯỜNG ĐẠI HỌC TÂY NGUYÊN

KHOA KHTN&CN

BÁO CÁO MÔN HỌC


LẬP TRÌNH ỨNG DỤNG MÃ NGUỒN MỞ

ĐỀ TÀI: LẬP TRÌNH ỨNG DỤNG XEM THỜI TIẾT VÀ SỐ LIỆU


COVID 19

Sinh viên: Hoàng Ngọc Thành 18103080


Lớp: CNTT K18
Khóa: 2018 – 2022
Ngành: Công nghệ thông tin
Giảng viên hướng dẫn:
ThS. Trương Thị Hương Giang

Đắk Lắk, tháng 09 năm 2021

1
TRƯỜNG ĐẠI HỌC TÂY NGUYÊN
KHOA KHTN&CN

BÁO CÁO MÔN HỌC


LẬP TRÌNH ỨNG DỤNG MÃ NGUỒN MỞ

ĐỀ TÀI: LẬP TRÌNH ỨNG DỤNG XEM THỜI TIẾT VÀ SỐ LIỆU


COVID 19

Sinh viên: Hoàng Ngọc Thành 18103080


Lớp: CNTT K18
Khóa: 2018 – 2022
Ngành: Công nghệ thông tin
Giảng viên hướng dẫn:
ThS. Trương Thị Hương Giang

Đắk Lắk, tháng 09 năm 2021


2
LỜI CẢM ƠN
Trong thời gian làm đồ án môn học, em đã nhận được nhiều sự giúp đỡ, đóng
góp ý kiến và chỉ bảo nhiệt tình của thầy cô và bạn bè.
Em xin gửi lời cảm ơn chân thành đến cô Ths. Trương Thị Hương Giang,
giảng viên khoa Khoa học Tự nhiên và Công nghệ, cô đã tận tình hướng dẫn,
chỉ bảo em trong suốt quá trình đồ án.
Em cũng xin chân thành cảm ơn các thầy cô giáo trong trường Đại học Tây
Nguyên nói chung và các thầy cô trong khoa Khoa học Tự nhiên và Công
nghệ nói riêng đã dạy dỗ cho chúng em những kiến thức về các môn học
chuyên ngành Công nghệ thông tin, giúp chúng em có được cơ sở lý thuyết
vững vàng và tạo điều kiện giúp đỡ chúng em trong suốt quá trình học tập.
Cuối cùng, em xin chân thành cảm ơn gia đình và bạn bè đã luông tạo đièu
kiện, quan tâm, giúp đỡ động viên em trong suốt quá trình học tập và hoàn
thành đồ án này.

Em xin chân thành cảm ơn!

3
MỤC LỤC
LỜI CẢM ƠN ................................................................................................... 3
DANH MỤC HÌNH ẢNH ................................................................................ 6
CHƯƠNG 1: GIỚI tHIỆU VỀ FLUTTER ....................................................... 7
1.1 Giới thiệu................................................................................................. 7
1.1.1 Giới thiệu chung ............................................................................... 7
1.2 Lịch sử phát triển .................................................................................... 7
1.3 Mục tiêu phát triển .................................................................................. 7
1.4 So sánh ưu nhược điểm ........................................................................... 8
1.4.1 Ưu điểm ............................................................................................ 8
1.4.2 Nhược điểm ...................................................................................... 9
1.4.3 So sánh với framework khác ............................................................ 9
1.5 Hướng dẫn cài đặt ................................................................................. 10
1.6 Cấu trúc trong Flutter ............................................................................ 14
CHƯƠNG 2: PHÂN TÍCH YÊU CẦU .......................................................... 15
2.1 Giới thiệu và cách thức giải quyết ........................................................ 15
2.2 Phân tích hệ thống ................................................................................. 16
2.3 Yêu cầu hệ thống................................................................................... 16
CHƯƠNG 3: XÂY DỰNG ỨNG DỤNG ...................................................... 17
3.1 Tạo mới ứng dụng trong Flutter ............................................................ 17
3.2 Xây dựng cấu trúc thư mục ................................................................... 18
3.3 Cài đặt các gói bổ sung ......................................................................... 18
3.4 Xây dựng bố cục cho ứng dụng ............................................................ 19
3.5 Xây dựng các thành phần cho ứng dụng ............................................... 21
3.5.1 Xây dựng thanh navigation bên dưới ............................................. 21
3.5.2 Xây dựng thanh tìm kiếm............................................................... 22
3.5.3 Xây dựng chức năng hiển thị nhiệt độ thành phố tạm thời ............ 23
3.5.4 Xây dựng giao diện hiển thị thời tiết sau khi tìm kiếm ................. 25

4
3.5.5 Xây dựng thanh navigation chia thế giới và quốc gia ................... 29
3.5.6 Xây dựng giao diện covid 19 thế giới ............................................ 30
3.5.7 Xây dựng thanh tìm kiếm quốc gia ................................................ 33
3.5.8 Xây dựng giao diện covid 19 quốc gia .......................................... 35
3.6 Xây dựng chức năng rest API ............................................................... 38
3.7 Xây dựng chức năng nhập vào ô tìm kiếm covid quốc gia hiện từ liên
quan ............................................................................................................. 39
CHƯƠNG 4: KẾT QUẢ ................................................................................. 41
4.1 Cấu trúc thư mục sau khi hoàn thành dự án.......................................... 41
4.2 Kết quả .................................................................................................. 41
TÀI LIỆU THAM KHẢO ............................................................................... 43

5
DANH MỤC HÌNH ẢNH
Hình ảnh 1: Biểu đồ so sánh flutter và react native .................................... 9
Hình ảnh 2: Tải gói flutter SDK .................................................................. 10
Hình ảnh 3: Giải nén flutter SDK................................................................ 10
Hình ảnh 4: Edit the system enviroment variables .................................... 11
Hình ảnh 5: Cấu hình ................................................................................... 11
Hình ảnh 6: Path ........................................................................................... 12
Hình ảnh 7: Dán đường dẫn thư mục flutter SDK .................................... 12
Hình ảnh 8: Kiểm tra cài đặt flutter ........................................................... 13
Hình ảnh 9: Sửa lỗi không nhận Android Studio ...................................... 13
Hình ảnh 10: Sửa lỗi Android toolchain ..................................................... 13
Hình ảnh 11: Cài đặt thành công ................................................................. 14
Hình ảnh 12: Cấu trúc thư mục flutter ....................................................... 14
Hình ảnh 13: Rest API .................................................................................. 15
Hình ảnh 14: Flutter sau khi được tạo mới ................................................ 17
Hình ảnh 15: Chương trình demo ............................................................... 17
Hình ảnh 16: Cấu trúc cây thư mục sau khi tạo mới ................................ 18
Hình ảnh 17: Các gói bổ sung ...................................................................... 19
Hình ảnh 18: Giao diện tìm kiếm thời tiết thành phố ............................... 19
Hình ảnh 19: Giao diện thông tinm chi tiết của thành phố....................... 20
Hình ảnh 20: Giao diện thông tin covid của thế giới ................................. 20
Hình ảnh 21: Giao diện thông tin covid được tìm kiếm ............................ 21
Hình ảnh 22: Kết quả của giao diện dự báo thời tiết................................. 41
Hình ảnh 23: Kết quả của giao diện covid 19 ............................................. 42

6
CHƯƠNG 1: GIỚI THIỆU VỀ FLUTTER
1.1 Giới thiệu
1.1.1 Giới thiệu chung
Flutter là mobile UI framework của Google để tạo ra các giao diện chất
lượng cao trên iOS và Android trong khoảng thời gian ngắn. Flutter hoạt động
với những code sẵn có được sử dụng bởi các lập trình viên, các tổ chức.Flutter
hoàn toàn miễn phí và cũng là mã nguồn mở.
Các ứng dụng được xây dựng với Flutter hầu như không thể phân biệt
với những ứng dụng được xây dựng bằng cách sử dụng Android SDK, cả về
giao diện và hiệu suất. Hơn nữa, với những tinh chỉnh nhỏ, chúng có thể chạy
trên thiết bị iOS.
Flutter sử dụng Dart, một ngôn ngữ nhanh, hướng đối tượng với nhiều
tính năng hữu ích như mixin, generic, isolate, và static type.
Flutter có các thành phần UI của riêng nó, cùng với một cơ chế để kết
xuất chúng trên nền tảng Android và iOS. Hầu hết các thành phần giao diện
người dùng, đều sẵn dùng, phù hợp với các nguyên tắc của Material Design.
1.2 Lịch sử phát triển
➢ Tháng 5 năm 2017 phát hành bản alpha đầu tiên.
➢ Tháng 8 năm 2017 phát hành ứng dụng thương mại đầu tiên.
➢ Tháng 3 năm 2018 phát hành bản beta đầu tiên.
➢ Tháng 5 năm 2018 flutter tham gia 100 đại diện dành đầu của github.
➢ Tháng 12 năm 2018 Google phát hành bản flutter 1.0 và là bản ổn định
để có thể dung.
➢ Tháng 2 năm 2019 tại đại hội thế giới di động phát hành bản flutter 1.2.
➢ Tháng 5 năm 2019 flutter cho phiên bản xem trước trên web.
➢ Tháng 9 năm 2019 flutter phát hành bản 1.9.
➢ Tháng 12 năm 2019 Flutter interact Flutter 1.12 và Dart 2.7 , Flutter web
hỗ trợ trong bản beta.
1.3 Mục tiêu phát triển
Flutter được phát triển để xây dựng giao diện có các hiệu ứng đa dạng và
phức tạp giúp nâng cao tính tương tác cho sản phẩm, làm cho sản phẩm trở nên
7
đẹp, đa dạng và sinh động, giúp lập trình viên giảm được rất nhiều thời gian
không cần thiết khi xây dựng sản phẩm.
1.4 So sánh ưu nhược điểm
1.4.1 Ưu điểm
Flutter là bộ open-source SDK , tức là miễn phí và mở – cộng đồng
developer có thể cùng tham gia phát triển.
Giao diện đẹp: Flutter cung cấp rất nhiều các widget, với nhiều sự lựa
chọn. Giao diện khá đẹp và sắc nét. các giao diện lập trình ứng dụng (API)
chuyển động phong phú, scroll tự nhiên mượt mà và tự nhận thức được nền
tảng
Viết code ứng dụng nhanh hơn: Như các bạn đã biết, tầng Framework
của Flutter được viết bằng Dart- một ngôn ngữ hướng đối tượng hỗ trợ JIT(Just
In Time), tức là hỗ trợ hot reload trong quá trình viết code. Với hot reload bạn
có thể cập nhật ứng dụng rất nhanh khi source code của bạn thay đổi mà không
cần phải build lại bằng việc nhấn nút hot reload. Trong quá trình viết ứng dụng,
bạn sẽ thấy rõ điểm ưu việt này của hot reload.
Flutter dễ học và dễ sử dụng cách dùng nó để tạo ứng dụng di động vô
cùng đơn giản. Trước kia bạn đã dùng Java, Swift, React Native, thì khi sử dụng
sang Flutter bạn sẽ thấy điểm khác biệt rõ nét. là bạn có thể tạo ứng dụng gốc
thực sự mà không cần code nhiều, hạn chế được nhiều lỗi.
Hiệu năng mạnh mẽ: Static language nhưng với syntax hiện đại, compiler
linh động giữa AOT (for archive, build prod) và JIT (for development, hot
reload).
Có thể chạy được giả lập mobile ngay trên web, tiện cho việc phát triển.
Các bộ đo lường chỉ số hiệu suất được hỗ trợ sẵn giúp lập trình viên kiểm soát
tốt hiệu suất của ứng dụng.
Framework hiện đại: Dễ dàng tạo giao diện người dùng của bạn với
framework hiện đại của Flutter và tập hợp các platform, layout và widget phong
phú. Giải quyết các thách thức giao diện người dùng khó khăn của bạn với các
API mạnh mẽ và linh hoạt cho 2D, animation, gesture, hiệu ứng và hơn thế nữa.
Hỗ trợ đa nền tảng: Android, iOS, Desktop, Linux, Embbed System.

8
Thời gian xây dựng ứng dụng nhanh hơn, chi phí thấp hơn: Viết code
nhanh, chỉ 1 basecode chạy trên 2 nền tảng Android, iOS vì vậy thời gian test,
fix bugs sẽ nhanh hơn, tiết kiệm chi phí xây dựng app hơn
1.4.2 Nhược điểm
Thư viện và Supports hạn chế hơn so với native SDK. Vì Flutter SDK
mới chỉ phát hành chính thức vào năm 2017 nên cộng đồng chưa mạnh được
như các nền tảng native.
Kích thước file lớn: Ví dụ cùng một app “Hello world”, App Flutter có
kích thước là 4.7MB, App Kotlin là 550KB, App native Java là : 539KB. Cũng
dễ hiểu thôi, bởi cấu trúc của Flutter SDK chứa các thư viện để xử lý trên cả
iOS và Android.
Bộ render UI gần như viết lại, không liên quan tới UI có sẵn của
Framework native, dẫn đến memory sử dụng khá nhiều
Phải học thêm ngôn ngữ DART. Dù dễ và thân thiện nhưng đây cũng là
1 rào cản quan trọng cần cân nhắc.
Mô hình dữ liệu mới: bloc pattern, DART Streaming; nếu đã quen
với Redux khi làm phát triển React Native, bạn sẽ mất thời gian để học thêm
mô hình dữ liệu trong Flutter, mặc dù nó không khó.
Update quá nhanh… ngủ dậy sau một giấc thấy version tăng 2 số là bình
thường. Hiện đã stable nhiều hơn, với khi update cũng hiếm bị breaking change
(lỗi source cũ).
1.4.3 So sánh với framework khác

Hình ảnh 1: Biểu đồ so sánh flutter và react native

9
1.5 Hướng dẫn cài đặt
Đầu tiên chúng ta vào trang web của Flutter để tiến hành cài đặt theo
đường link sau https://flutter.dev/docs/get-started/install/windows

Hình ảnh 2: Tải gói flutter SDK


Sau đó chúng ta giải nén và bỏ vào Documents

Hình ảnh 3: Giải nén flutter SDK


Tiếp theo chúng ta coppy đường dẫn có chứa tệp flutter trên và bỏ vào
trong Edit the system enviroment variables.

10
Hình ảnh 4: Edit the system enviroment variables

Hình ảnh 5: Cấu hình

11
Hình ảnh 6: Path

Hình ảnh 7: Dán đường dẫn thư mục flutter SDK

12
Sau đó mở cmd kiểm tra với lệnh flutter doctor, sẽ hiển thị được như bên
dưới hình

Hình ảnh 8: Kiểm tra cài đặt flutter


Tiếp theo chúng ta gõ lệnh flutter config –android-studio-
dir=”C:\Program Files\Android\Android Studio”

Hình ảnh 9: Sửa lỗi không nhận Android Studio


Tiếp theo gõ lệnh flutter doctor –android-licenses và màn hình console
sẽ thực hiện lệnh và khi có chỗ hỏi y/n chúng ta chọn yes để cấp phép cho flutter

Hình ảnh 10: Sửa lỗi Android toolchain


13
Sau đó tất cả đều hiện tích xanh là chúng ta đã hoàn thành bước cài đặt.

Hình ảnh 11: Cài đặt thành công


1.6 Cấu trúc trong Flutter
Cấu trúc của flutter sau khi đợc tạo mới sẽ có các thư mục như hình bên
dưới.

Hình ảnh 12: Cấu trúc thư mục flutter

14
CHƯƠNG 2: PHÂN TÍCH YÊU CẦU
2.1 Giới thiệu và cách thức giải quyết
Khi xây dựng ứng dụng xem thông tin của thời tiết và xem số lượng ca
nhiễm Covid 19 sẽ có 2 phần là Backend và Fontend. Backend có nhiệm vụ là
lấy dữ liệu về thời tiết và covid 19 ( nhiệt độ, độ ẩm, số ca nhiễm, tử vong…).
Về phần Fontend đóng vai trò là giao diện để người dùng tương tác và hiển
thị dữ liệu ra cũng như các chức năng của ứng dụng.
Phần giao diện của ứng dụng gồm 2 thành phần là xem dữ liệu thời tiết
và dữ liệu thống kê về tình hình Covid 19
Phần còn lại chính là Backend được lấy dữ liệu thông qua API, ứng
dụng sẽ đọc dữ liệu từ API và xử lý dữ liệu và hiển thị lên phía Fontend cho
người dùng.

Hình ảnh 13: Rest API

15
2.2 Phân tích hệ thống

Tên chức năng Mô tả chức năng


Hiển thị tên thành phố đang sống và
Thời tiết
nhiệt độ cùng với tình trạng thời tiết
Tìm kiếm và nhập tên thành phố
Tìm kiếm thành phố
muốn xem thời tiết
Bấm chưc năng này sẽ hiển thị ra
Covid 19 tình hình covid trên thế giới và thành
phố
Hiển thị ra số liệu ca nhiễm, tử vong,
Covid thế giới
lành bệnh trên toàn thế giới
Hiển thị ra thanh tìm kiếm tên quốc
Covid quốc gia
gia
Nhập tên quốc gia sau đó sẽ hiển thị
Tìm kiếm quốc gia dữ liệu covid về ca nhiễm, tử vong,
lành bệnh trong nước đó

2.3 Yêu cầu hệ thống


- Tốc độ xử lý nhanh, mượt ít tốn thời gian.
- Giao diện thân thiện dễ dùng gọn gàng sạch đẹp.

16
CHƯƠNG 3: XÂY DỰNG ỨNG DỤNG
3.1 Tạo mới ứng dụng trong Flutter
Để tạo mới một dự án flutter chúng ta khởi động cmd và tìm đến thư
mục chứa dự án và gõ câu lệnh flutter create myapp với myapp là tên của dự
án sau đó chúng ta sẽ có được.

Hình ảnh 14: Flutter sau khi được tạo mới


Sau khi chạy dự án chúng ta sẽ có được demo như sau.

Hình ảnh 15: Chương trình demo

17
3.2 Xây dựng cấu trúc thư mục

Hình ảnh 16: Cấu trúc cây thư mục sau khi tạo mới
➢ Thư mục lib chứa tất cả các tệp liên quan đến fontend và backend.
➢ Thư mục pubspec.yaml dùng để chứa tất cả các liên kết đến các thư viện
hỗ trợ cho flutter.
➢ Thư mục android và ios chứa các file liên quan đến việc chạy ứng dụng
trên nền tảng android và ios cũng như để tinh chỉnh cho phù hợp với yêu
cầu lập trình viên.
➢ Thư mục build là nơi mà chúng ta chuyển đổi từ code ra ứng dụng để
chạy trên nền tảng android hay ios.
3.3 Cài đặt các gói bổ sung
➢ cupertino_icons: giúp flutter đùng được icons hỗ trợ bên ngoài.
➢ font_awesome_flutter: giúp sử dụng nhiều font hơn.
➢ http: để lấy dữ liệu từ các API http
18
Hình ảnh 17: Các gói bổ sung
3.4 Xây dựng bố cục cho ứng dụng

Hình ảnh 18: Giao diện tìm kiếm thời tiết thành phố

19
Hình ảnh 19: Giao diện thông tinm chi tiết của thành phố

Hình ảnh 20: Giao diện thông tin covid của thế giới

20
Hình ảnh 21: Giao diện thông tin covid được tìm kiếm
3.5 Xây dựng các thành phần cho ứng dụng
3.5.1 Xây dựng thanh navigation bên dưới

Phần code của giao diện:


Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _widgetOption.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
selectedItemColor: kPrimaryColor,
unselectedItemColor: Colors.grey,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(FontAwesomeIcons.cloud),
label: "Thời Tiết",
),
BottomNavigationBarItem(

21
icon: Icon(FontAwesomeIcons.virus),
label: "Covid-19",
)
],
currentIndex: _selectedIndex,
onTap: (int index) {
setState(() {
_selectedIndex = index;
});
},
),
);
}

3.5.2 Xây dựng thanh tìm kiếm

Phần code của giao diện:


Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 20, 0),
child: TextField(
controller: city,
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: const BorderRadius.all(
Radius.circular(30.0),
),
borderSide: BorderSide(
color: Colors.black, width: 2.0),
),
enabledBorder: OutlineInputBorder(
borderRadius: const BorderRadius.all(
Radius.circular(30.0),
),
borderSide: BorderSide(
color: Colors.black, width: 2.0),
),
hintText: 'Nhập Thành Phố',
22
suffixIcon: IconButton(
icon:
Icon(Icons.search, color: Colors.black),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
WeatherSecondPage(
text: city.text,
),
));
print(city.text);
},
),
),
),
),
]),

3.5.3 Xây dựng chức năng hiển thị nhiệt độ thành phố tạm thời

Container(
height: 200,
margin: EdgeInsets.fromLTRB(20, 0, 20, 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(50.0),
),
color: Color(0xff9FA8DA),
boxShadow: [
BoxShadow(
color: Colors.grey, blurRadius: 20.0, spreadRadius: -10.0,

23
offset: Offset(0.0,0.0,),
)
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
cityname != null
? cityname.toString()
: "Loading",
style: TextStyle(
color:Colors.black, fontSize: 45.0, fontWeight: FontWeight.bold,
letterSpacing: 3, fontFamily: 'JosefinSans'
),
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(children: <Widget>[
Icon(Icons.thermostat_rounded),
Text(
temp != null
? temp.toString() + "\u00b0"
: "Loading",
style: TextStyle(color: Colors.black,fontSize: 30.0,
fontFamily: 'JosefinSans',letterSpacing: 3,
),
),
]),
),
Padding(
padding: EdgeInsets.only(top: 20.0),
child: Row(children: <Widget>[
Icon(Icons.cloud_circle_sharp),
Text(
currently != null ? currently.toString() : "Loading",
style: TextStyle(color: Colors.black,fontSize: 30.0,
fontFamily: 'JosefinSans'
),
),
]),
),
],
),
]),
),

24
3.5.4 Xây dựng giao diện hiển thị thời tiết sau khi tìm kiếm

Phần code giao diện:


Widget build(BuildContext context) {
return Scaffold(
body: Column(children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 2.2,
width: MediaQuery.of(context).size.width,
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage('assets/weather.gif'),
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.6), BlendMode.dstATop),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 20,
),
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
FontAwesomeIcons.search,
size: 30,
color: Colors.black,
),

25
),
Padding(
padding: EdgeInsets.only(top: 40, bottom: 20),
child: Text(
"Currently in ",
style: TextStyle(
color: Colors.black54,
fontSize: 35.0,
fontWeight: FontWeight.bold,
letterSpacing: 2,
fontFamily: 'JosefinSans'),
),
),
SizedBox(height: 20),
Text(
widget.text.toUpperCase(),
style: TextStyle(
color: Colors.black,
fontSize: 30,
fontWeight: FontWeight.bold,
letterSpacing: 3,
fontFamily: 'JosefinSans'),
),
SizedBox(height: 50),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(children: <Widget>[
Icon(Icons.thermostat_rounded),
Text(
temp != null ? temp.toString() + "\u00b0" :"Loading",
style: TextStyle(
color: Colors.black,
fontSize: 30.0,
//fontWeight: FontWeight.w700,
fontFamily: 'JosefinSans',
letterSpacing: 3,
),
),
]),
),
Padding(
padding: EdgeInsets.only(top: 20.0),
child: Row(children: <Widget>[
Icon(Icons.cloud_circle_sharp),
SizedBox(
width: 10,
),
Text(

26
currently != null ? currently.toString() : "Loading",
style: TextStyle(
color: Colors.black,
fontSize: 30.0,
//fontWeight: FontWeight.w700,
fontFamily: 'JosefinSans'),
),
]),
),
],
),
]),
),
Expanded(
child: Container(
color: Color.fromRGBO(236, 229, 220, 0.6),
child: Container(
margin: EdgeInsets.fromLTRB(30, 50, 30, 80),
//color: Colors.red,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(
Radius.circular(30.0),
),
color: Colors.white,
boxShadow: [
//background color of box
BoxShadow(
color: Colors.grey,
blurRadius: 20.0, // soften the shadow
spreadRadius: -10.0, //extend the shadow
offset: Offset(
0.0, // Move to right 10 horizontally
0.0, // Move to bottom 10 Vertically
),
)
],
),
//child: Padding(
//padding: EdgeInsets.all(30.0),
child: ListView(
children: <Widget>[
ListTile(
leading: FaIcon(FontAwesomeIcons.thermometerHalf,
color: Colors.black),
title: Text("Temperature",
style: TextStyle(
fontFamily: 'Syne', fontWeight:FontWeight.bold)),
trailing: Text(
temp != null ? temp.toString() + "\u00b0" :"Loading",

27
style: TextStyle(fontSize: 15)),
),
ListTile(
leading:
FaIcon(FontAwesomeIcons.cloud, color: Colors.black),
title: Text("Weather",
style: TextStyle(
fontFamily: 'Syne', fontWeight:FontWeight.bold)),
trailing: Text(
description != null
? description.toString()
: "Loading",
style: TextStyle(fontSize: 15)),
),
ListTile(
leading:
FaIcon(FontAwesomeIcons.tint, color: Colors.black),
title: Text("Humidity",
style: TextStyle(
fontFamily: 'Syne', fontWeight:FontWeight.bold)),
trailing: Text(
humidity != null
? humidity.toString() + "%"
: "Loading",
style: TextStyle(fontSize: 15)),
),
ListTile(
leading:
FaIcon(FontAwesomeIcons.wind, color: Colors.black),
title: Text("Wind Speed",
style: TextStyle(
fontFamily: 'Syne', fontWeight:FontWeight.bold)),
trailing: Text(
windspeed != null
? windspeed.toString() + "m/s"
: "Loading",
style: TextStyle(fontSize: 15)),
),
],
),
)),
),
]),
);
}

28
3.5.5 Xây dựng thanh navigation chia thế giới và quốc gia

Phần code giao diện:


Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
backgroundColor: kPrimaryColors,
elevation: 0,
title: Text("Covid 19 App"),
centerTitle: true,
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: kPrimaryColors,
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(50),
bottomLeft: Radius.circular(50)),
),
child: AnimatedSwitcher(
duration: Duration(milliseconds: 250),
child: navigationStatus == NavigationStatus.GLOBAL
? Global()
: Country(),
),
),
),
Container(
height: size.height * 0.1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
NavigationOption(

29
title: "Thế Giới",
selected: navigationStatus == NavigationStatus.GLOBAL,
onSelected: () {
setState(() {
navigationStatus = NavigationStatus.GLOBAL;
});
},
),
NavigationOption(
title: "Quốc Gia",
selected: navigationStatus == NavigationStatus.COUNTRY,
onSelected: () {
setState(() {
navigationStatus = NavigationStatus.COUNTRY;
});
},
)
],
),
),
],
),
);
}

3.5.6 Xây dựng giao diện covid 19 thế giới

Phần code giao diện:

30
Widget build(BuildContext context) {
return Column(
children: [
buildCard(
"Tổng Ca Nhiễm Covid Ghi Nhận",
summary?.cases ?? 0,
summary?.todayCases ?? 0,
kConfirmedColor,
),
buildCard(
"Tổng Số Ca Hiện Tại",
summary?.active ?? 0,
summary?.todayCases ?? 0,
kActiveColor,
),
buildCard(
"Tổng Số Ca Hồi Phục",
summary?.recovered ?? 0,
summary?.todayRecovered ?? 0,
kRecoveredColor,
),
buildCard(
"Tổng Số Ca Chết",
summary?.deaths ?? 0,
summary?.todayDeaths ?? 0,
kDeathColor,
),
],
);
}

Widget buildCard(String title, int totalCount, int todayCount, Color color) {


return Card(
elevation: 1,
child: Container(
height: 90,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Column(
children: [
Text(
title,
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
Expanded(
child: Container(),
31
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Tổng",
style: TextStyle(
color: color,
fontWeight: FontWeight.bold,
fontSize: 15,
),
),
Text(
totalCount.toString().replaceAllMapped(
reg, (Match match) => '${match[1]}.'),
style: TextStyle(
color: color,
fontWeight: FontWeight.bold,
fontSize: 28,
))
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
"Hôm nay",
style: TextStyle(
color: color,
fontWeight: FontWeight.bold,
fontSize: 15,
),
),
Text(
todayCount.toString().replaceAllMapped(
reg, (Match match) => '${match[1]}.'),
style: TextStyle(
color: color, fontWeight: FontWeight.bold,
fontSize: 28,
))
],
),
],
)
],
)),
);
}

32
3.5.7 Xây dựng thanh tìm kiếm quốc gia

Widget build(BuildContext context) {


return FutureBuilder(
future: countryList,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text("Error"),
);
}
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(
child: Text("Loading"),
);
default:
return !snapshot.hasData
? Center(
child: Text(
"Empty",
),
)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding:
EdgeInsets.symmetric(horizontal: 4, vertical: 6),
child: Text(
"Tên Quốc Gia",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
),
TypeAheadFormField<CountryModel?>(
textFieldConfiguration: TextFieldConfiguration(
controller: this._typeAheadController,

33
decoration: InputDecoration(
hintText: 'Nhập tên quốc gia',
hintStyle: TextStyle(fontSize: 16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
borderSide: BorderSide(
width: 0,
style: BorderStyle.none,
),
),
filled: true,
fillColor: Colors.grey[200],
contentPadding: EdgeInsets.all(20),
prefixIcon: Padding(
padding: EdgeInsets.only(left: 24.0, right: 16.0),
child: Icon(
Icons.search,
color: Colors.black,
size: 28,
),
),
),
),
suggestionsCallback: CovidService.getCountrySummary,
itemBuilder: (context, CountryModel? suggestion) {
final country = suggestion!;
return ListTile(
title: Text(country.country),
);
},
transitionBuilder:
(context, suggestionsBox, controller) {
return suggestionsBox;
},
onSuggestionSelected: (CountryModel? suggestion) {
this._typeAheadController.text =
suggestion?.country ?? '';
setState(() {
summaryList = CovidService.getCountrySummary(
suggestion!.country);
});
},
),
SizedBox(height: 8),
FutureBuilder<List<CountryModel>>(
future: summaryList,
builder: (context, snapshot) {
if (snapshot.hasError)
return Center(
child: Text("Error"),
);

34
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(
child: Text("Loading"),
);
default:
return !snapshot.hasData
? Center(
child: Text("Empty"),
)
: CountryStatistics(
summaryList:
snapshot.data as List<CountryModel>,
);
}
},
),
],
);
}
},
);
}

3.5.8 Xây dựng giao diện covid 19 quốc gia

35
Phần code giao diện:
Widget build(BuildContext context) {
return Column(
children: [
buildCard(
"Số Ca Ghi Nhận",
summaryList[summaryList.length - 1].cases,
kConfirmedColor,
"Số Ca Nhiễm",
summaryList[summaryList.length - 1].active,
kActiveColor,
),
buildCard(
"Số Ca Hồi Phục",
summaryList[summaryList.length - 1].recovered,
kRecoveredColor,
"Số Ca Chết",
summaryList[summaryList.length - 1].deaths,
kDeathColor,
),
buildCard(
"Ca Nhiễm / Ngày",
summaryList[summaryList.length - 1].todayCases,
kConfirmedColor,
"Ca Nhiễm / 1 Triệu",
summaryList[summaryList.length - 1].casesPerOneMillion,
kConfirmedColor,
),
buildCard(
"Ca Hồi Phục / Ngày",
summaryList[summaryList.length - 1].todayRecovered,
kRecoveredColor,
"Ca Chết / Ngày",
summaryList[summaryList.length - 1].todayDeaths,
kDeathColor,
),
],
);
}

Widget buildCard(String leftTitle, int leftValue, Color leftColor,


String rightTitle, int rightValue, Color rightColor) {
return Card(
elevation: 1,
child: Container(
height: 70,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[

36
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
leftTitle,
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
Text(
leftValue
.toString()
.replaceAllMapped(reg, (Match match) => '${match[1]}.'),
style: TextStyle(
color: leftColor,
fontWeight: FontWeight.bold,
fontSize: 28,
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
rightTitle,
style: TextStyle(
color: Colors.grey, fontWeight: FontWeight.bold,
fontSize: 14,
),
),
Text(
rightValue
.toString()
.replaceAllMapped(reg, (Match match) => '${match[1]}.'),
style: TextStyle(
color: rightColor, fontWeight: FontWeight.bold,
fontSize: 28,
),
),
],
),
],
),
),
);
}

37
3.6 Xây dựng chức năng rest API
class CovidService {
var data = [];
List<CountryModel> results = [];

String urlAll = "https://disease.sh/v3/covid-19/all";


String urlCountry = "https://disease.sh/v3/covid-19/countries";
String urlCity = "http://static.pipezero.com/covid/data.json";

Future<GlobalSummaryModel> getGlobalSummary() async {


final response = await http.get(Uri.parse(urlAll));
if (response.statusCode == 200) {
var summary = GlobalSummaryModel.fromJson(jsonDecode(response.body));
return summary;
} else {
throw Exception('Unexpected error occured!');
}
}

static Future<List<CountryModel>> getCountrySummary(String query) async {


final response =
await http.get(Uri.parse("https://disease.sh/v3/covid-19/countries"));
if (response.statusCode == 200) {
// print(response.body);
final List summaryList = json.decode(response.body);

return summaryList
.map((json) => CountryModel.fromJson(json))
.where((country) {
final countryLower = country.country.toLowerCase();
final queryLower = query.toLowerCase();
return countryLower.contains(queryLower);
}).toList();
} else {
throw Exception('error');
}
}

Future<List<CountryModel>> getCountryList() async {


final response = await http.Client().get(Uri.parse(urlCountry));

if (response.statusCode == 200) {
List countries = json.decode(response.body);
return countries.map((e) => CountryModel.fromJson(e)).toList();
} else {
throw Exception('Unexpected error occured!');
}
}

Future<List<CountryModel>> getCityList() async {

38
final response = await http.Client().get(Uri.parse(urlCity));

if (response.statusCode == 200) {
List city = json.decode(response.body);
return city.map((e) => CountryModel.fromJson(e)).toList();
} else {
throw Exception('Unexpected error occured!');
}
}
}

3.7 Xây dựng chức năng nhập vào ô tìm kiếm covid quốc gia hiện từ liên
quan

Phần code xử lý:


TypeAheadFormField<CountryModel?>(
textFieldConfiguration: TextFieldConfiguration(
controller: this._typeAheadController,
decoration: InputDecoration(
hintText: 'Nhập tên quốc gia',
hintStyle: TextStyle(fontSize: 16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),

39
borderSide: BorderSide(
width: 0,
style: BorderStyle.none,
),
),
filled: true,
fillColor: Colors.grey[200],
contentPadding: EdgeInsets.all(20),
prefixIcon: Padding(
padding: EdgeInsets.only(left: 24.0, right: 16.0),
child: Icon(
Icons.search,
color: Colors.black,
size: 28,
),
),
),
),
suggestionsCallback: CovidService.getCountrySummary,
itemBuilder: (context, CountryModel? suggestion) {
final country = suggestion!;
return ListTile(
title: Text(country.country),
);
},
transitionBuilder:(context, suggestionsBox, controller) {
return suggestionsBox;
},
onSuggestionSelected: (CountryModel? suggestion) {
this._typeAheadController.text = suggestion?.country ?? '';
setState(() {
summaryList = CovidService.getCountrySummary(suggestion!.country);
});
},
),

40
CHƯƠNG 4: KẾT QUẢ
4.1 Cấu trúc thư mục sau khi hoàn thành dự án

4.2 Kết quả

Hình ảnh 22: Kết quả của giao diện dự báo thời tiết

41
Hình ảnh 23: Kết quả của giao diện covid 19

42
TÀI LIỆU THAM KHẢO

[Tiếng Việt]
[1] Lập trình ứng dụng mã nguồn mở, ThS Trương Thị Giang Giang.
[Tiếng Anh]
[2] Tài liệu học lập trình Flutter trên trang web https://docs.flutter.dev/
[3] Tài liệu học lập trình Flutter trên trang web https://dart.dev/

43
Ý KIẾN CỦA NGƯỜI HƯỚNG DẪN

Nhận xét:

.............................................................................................................................
.............................................................................................................................
.............................................................................................................................
.............................................................................................................................
.............................................................................................................................
.............................................................................................................................
.............................................................................................................................

Đối với khóa luận tốt nghiệp (Đánh dấu và ký tên vào ý kiến chọn lựa
sau):

Ký tên

Đồng ý thông qua báo cáo

Không đồng ý thông qua báo cáo

Buôn Ma Thuột, ngày...tháng...năm 2021

NGƯỜI HƯỚNG DẪN

(Ký và ghi rõ họ tên)

44
Họ và tên sinh viên: Hoàng Ngọc Thành
Cán bộ hướng dẫn (ghi rõ học hàm học vị): Thạc sĩ Trương Thị Hương Giang

Tên đồ án: LẬP TRÌNH ỨNG DỤNG XEM THỜI TIẾT VÀ SỐ LIỆU
COVID 19

Điểm:

Đăk Lăk, ngày...tháng...năm 2021

SINH VIÊN

(Ký và ghi rõ họ tên)

XÁC NHẬN

CÁN BỘ HƯỚNG DẪN CHỦ TỊCH HỘI ĐỒNG

(Ký và ghi rõ họ tên) (Ký và ghi rõ họ tên)

45

You might also like