
Arkadaşlar merhaba; bildiğiniz üzere Google geçen yıllarda mobil uygulama geliştirme programı olan Flutter’ı tanıttı.
Flutter’ın artıları ve eksileri mutlaka vardır ancak bir burada bundan bahsetmeyeceğiz. Zaten diğer blog sitelerinde yeterince bu konulara yer açılmış.
Flutter Dart diliyle çalışan bir mobil uygulama geliştirme SDK’dır.
Bende burada Flutter kullanarak ortam denetleme sistemi için bir mobil uygulama örneği yapacağım.
İnternet üzerinden beğendiğim bir Flutter mobil uygulama teması indirdim.
Ortam denetleme sistemimizde olaması gerekenler Mustafa beyin de yazısında bahsettiği sensörler yardımı ile anolog verileri digital verileri çevirerek web servise post etmişti.
O halde bizim yapmamız gereken bu verileri Json veya XML şeklinde GET etmekdir.
Şimdi gelelim dosyalama sistemine flutter main.dart sayfasında uygulamanın başlamasını sağlar.
import 'package:fitness_app/pages/dashboard.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PiyonSoft ODS',
theme: ThemeData(
primarySwatch: Colors.blue,
primaryColor: Color(0XFF6D3FFF),
accentColor: Color(0XFF233C63),
fontFamily: 'Poppins',
),
home: Dashboard(),
);
}
}
main.dart
Biz ise verileri ve API kısmını farklı API içerisindeki verileri ayarı .DART sayfaları olarak oluşturacağız.
Böyle yapmamızın sebebi hikmeti kodların karışık olmaması ve ileride karşımıza çıkacak hataları kolayca tespit edilmemiz içindir.
Verileri bize düzenli şekilde gösterilmesi için ilk olarak dashboard.dart sayfası oluşturuyorum.
import 'package:flutter/material.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
import 'dart:convert';
import 'package:fitness_app/pages/API.dart';
import 'package:fitness_app/pages/User.dart';
class Dashboard extends StatefulWidget {
@override
_DashboardState createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
// var users = new List<User>();
var users = new List<User>();
_getUsers() {
API.getUsers().then((response) {
setState(() {
Iterable list = json.decode(response.body);
users = list.map((model) => User.fromJson(model)).toList();
});
});
}
initState() {
super.initState();
_getUsers();
}
dispose() {
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
elevation: 0,
titleSpacing: 10,
backgroundColor: Colors.white,
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
width: 40,
height: 40,
margin: EdgeInsets.only(right: 10),
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.network(
'https://i.pravatar.cc/100',
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Mehmet Albayram',
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(users.last.temp.toString(),
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 12,
),
),
],
),
],
),
actions: <Widget>[
FlatButton(
onPressed: () {},
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Container(
width: 50,
child: Icon(
Icons.notifications,
color: Theme.of(context).accentColor,
size: 35,
),
),
Positioned(
top: 0,
right: 0,
width: 20,
height: 20,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
color: Colors.red,
),
width: 20,
height: 20,
child: Center(
child: Text(
'Bildirim',
style: TextStyle(
color: Colors.white,
fontSize: 9,
),
),
),
),
),
],
),
)
],
),
body:SingleChildScrollView(
child: Padding(
padding: EdgeInsets.fromLTRB(25, 30, 25, 25),
child: Container(
width: MediaQuery.of(context).size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 70,
height: 70,
padding: EdgeInsets.all(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
color: Theme.of(context).primaryColor.withAlpha(50),
),
child: Image.asset(
'assets/img/bolt.png',
width: 60,
),
),
Padding(
padding: EdgeInsets.only(top: 30),
),
Text(users.last.temp.toString()+" °C",
style: TextStyle(
color: Theme.of(context).primaryColor,
fontSize: 80,
fontFamily: 'Bebas',
fontWeight: FontWeight.bold,
),
),
RaisedButton(
child: Text('Verileri Güncelle'),
color: Theme.of(context).primaryColor,
onPressed: (){
setState(() {
_getUsers();
});
},
),
Padding(
padding: EdgeInsets.only(top: 15),
),
Container(
padding: EdgeInsets.fromLTRB(50, 0, 50, 0),
width: MediaQuery.of(context).size.width,
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'18 Derece'.toUpperCase(),
style: TextStyle(
color: Colors.grey,
),
),
Text(
'22 Derece'.toUpperCase(),
style: TextStyle(
color: Colors.grey,
),
),
],
),
LinearPercentIndicator(
lineHeight: 8.0,
percent: 0.7,
linearStrokeCap: LinearStrokeCap.roundAll,
backgroundColor:
Theme.of(context).accentColor.withAlpha(30),
progressColor: Theme.of(context).primaryColor,
),
Padding(
padding: EdgeInsets.only(top: 30),
),
Text(
'PiyonSoft ODS'.toUpperCase(),
style: TextStyle(
color: Theme.of(context).accentColor,
fontFamily: 'Bebas',
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
Text(
'Güncel verileri aşığıda görebilirsiniz',
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 16,
),
),
],
),
),
Divider(
height: 25,
color: Colors.grey[300],
),
Container(
child: Row(
children: <Widget>[
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'SICAKLIK',
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
),
),
RichText(
text: TextSpan(
children: [
TextSpan(
text:'Bir',
style: TextStyle(
fontSize: 20,
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: ' °C',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'NEM',
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
),
),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'İki',
style: TextStyle(
fontSize: 20,
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: ' g/m3',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
'IŞIK',
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
),
),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Kapalı',
style: TextStyle(
fontSize: 20,
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: ' lm',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
)
],
),
),
Divider(
height: 25,
color: Colors.grey[300],
),
Container(
child: Row(
children: <Widget>[
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'HARAKET',
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
),
),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'YOK',
style: TextStyle(
fontSize: 20,
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: '-',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'DUMAN',
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
),
),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'YOK',
style: TextStyle(
fontSize: 20,
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: ' g/m3',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
),
Expanded(
flex: 3,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
'ALEV',
style: TextStyle(
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
),
),
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'YOK',
style: TextStyle(
fontSize: 20,
color: Theme.of(context).accentColor,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: ' lm',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
)
],
),
),
Padding(
padding: EdgeInsets.only(top: 10),
),
Divider(
height: 25,
color: Colors.grey[300],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'DETAYLAR',
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 24,
fontFamily: 'Bebas',
fontWeight: FontWeight.bold,
),
),
Row(
children: <Widget>[
Image.asset(
'assets/img/down_orange.png',
width: 20,
),
Padding(
padding: EdgeInsets.only(right: 15),
),
Text(
'Üç',
style: TextStyle(
color: Colors.orange,
fontWeight: FontWeight.bold,
),
)
],
)
],
),
Container(
height: 250,
padding: EdgeInsets.fromLTRB(0, 15, 0, 15),
child: ListView(
physics: ClampingScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: <Widget>[
StatCard(
title: 'Sıcaklık',
achieved: 200,
total: 350,
color: Colors.orange,
image: Image.asset('assets/img/bolt.png', width: 20),
),
StatCard(
title: 'Nem',
achieved: 350,
total: 300,
color: Theme.of(context).primaryColor,
image: Image.asset('assets/img/fish.png', width: 20),
),
StatCard(
title: 'IŞIK',
achieved: 100,
total: 200,
color: Colors.green,
image: Image.asset('assets/img/sausage.png', width: 20),
),StatCard(
title: 'Nem',
achieved: 350,
total: 300,
color: Theme.of(context).primaryColor,
image: Image.asset('assets/img/fish.png', width: 20),
),
StatCard(
title: 'IŞIK',
achieved: 100,
total: 200,
color: Colors.green,
image: Image.asset('assets/img/sausage.png', width: 20),
),
],
),
),
],
),
),
),
),
);
}
}
class StatCard extends StatelessWidget {
final String title;
final double total;
final double achieved;
final Image image;
final Color color;
const StatCard({
Key key,
@required this.title,
@required this.total,
@required this.achieved,
@required this.image,
@required this.color,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: 200,
margin: EdgeInsets.only(right: 10),
padding: EdgeInsets.fromLTRB(15, 5, 15, 5),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.grey[200],
width: 1,
),
borderRadius: BorderRadius.circular(5),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
title.toUpperCase(),
style: TextStyle(
color: Theme.of(context).accentColor.withAlpha(100),
fontSize: 14,
),
),
achieved < total
? Image.asset(
'assets/img/down_orange.png',
width: 20,
)
: Image.asset(
'assets/img/up_red.png',
width: 20,
),
],
),
Padding(
padding: EdgeInsets.only(top: 25),
),
CircularPercentIndicator(
radius: 80.0,
lineWidth: 8.0,
percent: achieved / (total < achieved ? achieved : total),
circularStrokeCap: CircularStrokeCap.round,
center: image,
progressColor: color,
backgroundColor: Theme.of(context).accentColor.withAlpha(30),
),
Padding(
padding: EdgeInsets.only(top: 25),
),
RichText(
text: TextSpan(children: [
TextSpan(
text: achieved.toString(),
style: TextStyle(
fontSize: 20,
color: Theme.of(context).accentColor,
),
),
TextSpan(
text: ' / $total',
style: TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 12,
),
),
]),
)
],
),
);
}
}
dashboard.dart
Sonra API’ nin bağlantı verileri ne türde çekmesi gerektiğini söyleyeceğimiz bir API.dart sayfası oluşturuyorum
import 'dart:async';
import 'package:http/http.dart' as http;
const baseUrl = "https://anaapiardesi/";
class API {
static Future getUsers() {
var url = baseUrl + "/apiadresdevamı";
return http.get(url);
}
}
@Deprecated("Use NoSuchMethod.withInvocation instead")
// ignore: non_constant_identifier_names
external NoSuchMethodError(Object receiver, Symbol memberName,
List positionalArguments, Map<Symbol, dynamic> namedArguments,
[@deprecated List existingArgumentNames]);
API.dart
Son olarak verileri bize nasıl geleceği ve ne şekilde dönüştürmemiz gerektiğini yazacağımız data.dart sayfasını oluşturuyorum.
class User {
String date;
double humanity;
int id;
double temp;
User(String date, double humanity, int id, double temp) {
this.date= date;
this.humanity = humanity;
this.id = id;
this.temp = temp;
}
User.fromJson(Map json)
: date = json['date'],
humanity = json['humanity'],
id = json['id'],
temp = json['temp'];
Map toJson() {
return {'date': date, 'humanity': humanity, 'id': id, 'temp': temp};
}
}
@Deprecated("Use NoSuchMethod.withInvocation instead")
// ignore: non_constant_identifier_names
external NoSuchMethodError(Object receiver, Symbol memberName,
List positionalArguments, Map<Symbol, dynamic> namedArguments,
[@deprecated List existingArgumentNames]);
user.dart
Arduino ile aldığımız verileri mobil uygulamamıza çekmiş olduk,
Daha detaylı incelemek isteyen arkadaşlar için tüm kodları paylaşacağım buraya tıklayarak ulaşabilirsiniz.
Merak ettiklerinizi yorumlardan sorabilirsiniz.