feat: integrate with Rest API, feature home latest data update
This commit is contained in:
parent
5ddc748bc9
commit
08c7012f1d
|
|
@ -2,7 +2,7 @@ class AppConstant {
|
||||||
static const String appName = 'Kebun Pintar';
|
static const String appName = 'Kebun Pintar';
|
||||||
static const String appVersion = '1.0.0';
|
static const String appVersion = '1.0.0';
|
||||||
|
|
||||||
static const String baseUrl = 'http://192.168.11.41:3333/api/';
|
static const String baseUrl = 'https://jx027dj4-3333.asse.devtunnels.ms/api';
|
||||||
|
|
||||||
static const String mqttServer = 'armadillo.rmq.cloudamqp.com';
|
static const String mqttServer = 'armadillo.rmq.cloudamqp.com';
|
||||||
static const String mqttUsername = 'obyskxhx:obyskxhx';
|
static const String mqttUsername = 'obyskxhx:obyskxhx';
|
||||||
|
|
@ -10,4 +10,19 @@ class AppConstant {
|
||||||
|
|
||||||
static const String soilTempInfo =
|
static const String soilTempInfo =
|
||||||
'Suhu tanah mengacu pada suhu tanah di permukaan atau pada kedalaman tertentu, yang berperan penting dalam pertumbuhan tanaman dan proses pertanian. Suhu ini memengaruhi perkecambahan benih, aktivitas akar, serta penyerapan air dan nutrisi, yang semuanya esensial bagi perkembangan tanaman. Selain itu, suhu tanah juga memengaruhi aktivitas mikroorganisme yang berkontribusi pada kesuburan tanah. Dalam pertanian pintar, sensor suhu tanah sering digunakan untuk memantau dan mengoptimalkan kondisi tanah, memastikan tanaman tumbuh dalam rentang suhu yang ideal.';
|
'Suhu tanah mengacu pada suhu tanah di permukaan atau pada kedalaman tertentu, yang berperan penting dalam pertumbuhan tanaman dan proses pertanian. Suhu ini memengaruhi perkecambahan benih, aktivitas akar, serta penyerapan air dan nutrisi, yang semuanya esensial bagi perkembangan tanaman. Selain itu, suhu tanah juga memengaruhi aktivitas mikroorganisme yang berkontribusi pada kesuburan tanah. Dalam pertanian pintar, sensor suhu tanah sering digunakan untuk memantau dan mengoptimalkan kondisi tanah, memastikan tanaman tumbuh dalam rentang suhu yang ideal.';
|
||||||
|
|
||||||
|
static const String npk1 = 'npk1';
|
||||||
|
static const String npk2 = 'npk2';
|
||||||
|
static const String dht = 'dht';
|
||||||
|
|
||||||
|
static const String soilTemp = 'soilTemperature';
|
||||||
|
static const String soilMoisture = 'soilMoisture';
|
||||||
|
static const String airTemp = 'viciTemperature';
|
||||||
|
static const String humidity = 'humidity';
|
||||||
|
static const String lightIntensity = 'lightIntensity';
|
||||||
|
static const String conductivity = 'conductivity';
|
||||||
|
static const String ph = 'ph';
|
||||||
|
static const String nitrogen = 'nitrogen';
|
||||||
|
static const String phosphorus = 'phosphorus';
|
||||||
|
static const String potassium = 'potassium';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,12 @@ String dateFormater(String date) {
|
||||||
return formatter.format(dateTime);
|
return formatter.format(dateTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String dateFormatterShort(String date) {
|
||||||
|
final DateTime dateTime = DateTime.parse(date);
|
||||||
|
final DateFormat formatter = DateFormat('yyyy-MM-dd');
|
||||||
|
return formatter.format(dateTime);
|
||||||
|
}
|
||||||
|
|
||||||
String getGreeting(String time) {
|
String getGreeting(String time) {
|
||||||
DateTime parsedTime = DateTime.parse(time);
|
DateTime parsedTime = DateTime.parse(time);
|
||||||
int hour = parsedTime.hour;
|
int hour = parsedTime.hour;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import 'package:agrilink_vocpro/core/constant/app_constant.dart';
|
import 'package:agrilink_vocpro/core/constant/app_constant.dart';
|
||||||
|
import 'package:agrilink_vocpro/core/extension/extention.dart';
|
||||||
import 'package:agrilink_vocpro/data/model/relay_response.dart';
|
import 'package:agrilink_vocpro/data/model/relay_response.dart';
|
||||||
|
import 'package:agrilink_vocpro/features/home/model/latest_data_response.dart';
|
||||||
|
import 'package:agrilink_vocpro/features/home/model/npk1_soil_temp_grafik.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
|
@ -27,4 +30,47 @@ class AppService {
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Npk1SoilTempGrafik> getNpk1SoilTempGrafik({
|
||||||
|
required String metric,
|
||||||
|
required String sensor,
|
||||||
|
}) async {
|
||||||
|
String dateNow = DateTime.now().toString();
|
||||||
|
String dateYesterday =
|
||||||
|
DateTime.now().subtract(Duration(days: 1)).toString();
|
||||||
|
final formatedDateNow = dateFormatterShort(dateNow);
|
||||||
|
final formatedDateYesterday = dateFormatterShort(dateYesterday);
|
||||||
|
try {
|
||||||
|
final result = await _dioWithoutInterceptor.get(
|
||||||
|
'/sensor/getData?metric=$metric&range[start]=$formatedDateYesterday&range[end]=$formatedDateNow&range[time_range]=HOURLY&sensor=$sensor',
|
||||||
|
);
|
||||||
|
if (result.statusCode == 200) {
|
||||||
|
print(result.data.toString());
|
||||||
|
final data = Npk1SoilTempGrafik.fromJson(result.data);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load data');
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
print(e);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<LatestDataResponse> getLatestData() async {
|
||||||
|
try {
|
||||||
|
final result = await _dioWithoutInterceptor.get(
|
||||||
|
'/sensor/getLatest',
|
||||||
|
);
|
||||||
|
if (result.statusCode == 200) {
|
||||||
|
final data = LatestDataResponse.fromJson(result.data);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load data');
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
print(e);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ class ControlProvider extends ChangeNotifier {
|
||||||
relayState = ResultState.loading;
|
relayState = ResultState.loading;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
try {
|
try {
|
||||||
|
print('try to get relay status...');
|
||||||
final result = await _appService.getRelayStatus();
|
final result = await _appService.getRelayStatus();
|
||||||
if (result.success == true) {
|
if (result.success == true) {
|
||||||
for (var element in result.data!) {
|
for (var element in result.data!) {
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ class ControlScreen extends StatelessWidget {
|
||||||
crossAxisCount: 2,
|
crossAxisCount: 2,
|
||||||
crossAxisSpacing: 16.r,
|
crossAxisSpacing: 16.r,
|
||||||
mainAxisSpacing: 16.r,
|
mainAxisSpacing: 16.r,
|
||||||
childAspectRatio: 1.4.h,
|
childAspectRatio: 1.35.h,
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
ControlButtonWidget(
|
ControlButtonWidget(
|
||||||
|
|
@ -85,9 +85,14 @@ class ControlScreen extends StatelessWidget {
|
||||||
title: 'Lampu Utama',
|
title: 'Lampu Utama',
|
||||||
subtitle: 'Relay 2',
|
subtitle: 'Relay 2',
|
||||||
isActive: provider.control_2,
|
isActive: provider.control_2,
|
||||||
onTap: () {},
|
onTap: () {
|
||||||
|
provider.control_2 != true
|
||||||
|
? provider.switchControl2(true)
|
||||||
|
: provider.switchControl2(false);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
]),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
class DhtGraphicResponse {
|
||||||
|
DataDht? data;
|
||||||
|
int? statusCode;
|
||||||
|
String? message;
|
||||||
|
|
||||||
|
DhtGraphicResponse({this.data, this.statusCode, this.message});
|
||||||
|
|
||||||
|
DhtGraphicResponse.fromJson(Map<String, dynamic> json) {
|
||||||
|
data = json['data'] != null ? DataDht.fromJson(json['data']) : null;
|
||||||
|
statusCode = json['statusCode'];
|
||||||
|
message = json['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (this.data != null) {
|
||||||
|
data['data'] = this.data!.toJson();
|
||||||
|
}
|
||||||
|
data['statusCode'] = statusCode;
|
||||||
|
data['message'] = message;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataDht {
|
||||||
|
List<Dht>? dht;
|
||||||
|
|
||||||
|
DataDht({this.dht});
|
||||||
|
|
||||||
|
DataDht.fromJson(Map<String, dynamic> json) {
|
||||||
|
if (json['dht'] != null) {
|
||||||
|
dht = <Dht>[];
|
||||||
|
json['dht'].forEach((v) {
|
||||||
|
dht!.add(Dht.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (dht != null) {
|
||||||
|
data['dht'] = dht!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dht {
|
||||||
|
int? hour;
|
||||||
|
double? vicitemperatureAvg;
|
||||||
|
double? vicihumidityAvg;
|
||||||
|
double? viciluminosityAvg;
|
||||||
|
|
||||||
|
Dht(
|
||||||
|
{this.hour,
|
||||||
|
this.vicitemperatureAvg,
|
||||||
|
this.vicihumidityAvg,
|
||||||
|
this.viciluminosityAvg});
|
||||||
|
|
||||||
|
Dht.fromJson(Map<String, dynamic> json) {
|
||||||
|
hour = json['hour'];
|
||||||
|
vicitemperatureAvg = json['vicitemperature_avg'];
|
||||||
|
vicihumidityAvg = json['vicihumidity_avg'];
|
||||||
|
viciluminosityAvg = json['viciluminosity_avg'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['hour'] = hour;
|
||||||
|
data['vicitemperature_avg'] = vicitemperatureAvg;
|
||||||
|
data['vicihumidity_avg'] = vicihumidityAvg;
|
||||||
|
data['viciluminosity_avg'] = viciluminosityAvg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,185 @@
|
||||||
|
class LatestDataResponse {
|
||||||
|
Data? data;
|
||||||
|
int? statusCode;
|
||||||
|
String? message;
|
||||||
|
|
||||||
|
LatestDataResponse({this.data, this.statusCode, this.message});
|
||||||
|
|
||||||
|
LatestDataResponse.fromJson(Map<String, dynamic> json) {
|
||||||
|
data = json['data'] != null ? Data.fromJson(json['data']) : null;
|
||||||
|
statusCode = json['statusCode'];
|
||||||
|
message = json['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (this.data != null) {
|
||||||
|
data['data'] = this.data!.toJson();
|
||||||
|
}
|
||||||
|
data['statusCode'] = statusCode;
|
||||||
|
data['message'] = message;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Data {
|
||||||
|
List<Dht>? dht;
|
||||||
|
List<Npk1>? npk1;
|
||||||
|
List<Npk2>? npk2;
|
||||||
|
|
||||||
|
Data({this.dht, this.npk1, this.npk2});
|
||||||
|
|
||||||
|
Data.fromJson(Map<String, dynamic> json) {
|
||||||
|
if (json['dht'] != null) {
|
||||||
|
dht = <Dht>[];
|
||||||
|
json['dht'].forEach((v) {
|
||||||
|
dht!.add(Dht.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (json['npk1'] != null) {
|
||||||
|
npk1 = <Npk1>[];
|
||||||
|
json['npk1'].forEach((v) {
|
||||||
|
npk1!.add(Npk1.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (json['npk2'] != null) {
|
||||||
|
npk2 = <Npk2>[];
|
||||||
|
json['npk2'].forEach((v) {
|
||||||
|
npk2!.add(Npk2.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (dht != null) {
|
||||||
|
data['dht'] = dht!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
if (npk1 != null) {
|
||||||
|
data['npk1'] = npk1!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
if (npk2 != null) {
|
||||||
|
data['npk2'] = npk2!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dht {
|
||||||
|
int? hour;
|
||||||
|
num? vicitemperatureAvg;
|
||||||
|
num? vicihumidityAvg;
|
||||||
|
num? viciluminosityAvg;
|
||||||
|
|
||||||
|
Dht(
|
||||||
|
{this.hour,
|
||||||
|
this.vicitemperatureAvg,
|
||||||
|
this.vicihumidityAvg,
|
||||||
|
this.viciluminosityAvg});
|
||||||
|
|
||||||
|
Dht.fromJson(Map<String, dynamic> json) {
|
||||||
|
hour = json['hour'];
|
||||||
|
vicitemperatureAvg = json['vicitemperature_avg'];
|
||||||
|
vicihumidityAvg = json['vicihumidity_avg'];
|
||||||
|
viciluminosityAvg = json['viciluminosity_avg'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['hour'] = hour;
|
||||||
|
data['vicitemperature_avg'] = vicitemperatureAvg;
|
||||||
|
data['vicihumidity_avg'] = vicihumidityAvg;
|
||||||
|
data['viciluminosity_avg'] = viciluminosityAvg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Npk1 {
|
||||||
|
int? hour;
|
||||||
|
num? soiltemperatureAvg;
|
||||||
|
num? soilhumidityAvg;
|
||||||
|
num? soilconductivityAvg;
|
||||||
|
num? soilphAvg;
|
||||||
|
num? soilnitrogenAvg;
|
||||||
|
num? soilphosphorusAvg;
|
||||||
|
num? soilpotassiumAvg;
|
||||||
|
|
||||||
|
Npk1(
|
||||||
|
{this.hour,
|
||||||
|
this.soiltemperatureAvg,
|
||||||
|
this.soilhumidityAvg,
|
||||||
|
this.soilconductivityAvg,
|
||||||
|
this.soilphAvg,
|
||||||
|
this.soilnitrogenAvg,
|
||||||
|
this.soilphosphorusAvg,
|
||||||
|
this.soilpotassiumAvg});
|
||||||
|
|
||||||
|
Npk1.fromJson(Map<String, dynamic> json) {
|
||||||
|
hour = json['hour'];
|
||||||
|
soiltemperatureAvg = json['soiltemperature_avg'];
|
||||||
|
soilhumidityAvg = json['soilhumidity_avg'];
|
||||||
|
soilconductivityAvg = json['soilconductivity_avg'];
|
||||||
|
soilphAvg = json['soilph_avg'];
|
||||||
|
soilnitrogenAvg = json['soilnitrogen_avg'];
|
||||||
|
soilphosphorusAvg = json['soilphosphorus_avg'];
|
||||||
|
soilpotassiumAvg = json['soilpotassium_avg'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['hour'] = hour;
|
||||||
|
data['soiltemperature_avg'] = soiltemperatureAvg;
|
||||||
|
data['soilhumidity_avg'] = soilhumidityAvg;
|
||||||
|
data['soilconductivity_avg'] = soilconductivityAvg;
|
||||||
|
data['soilph_avg'] = soilphAvg;
|
||||||
|
data['soilnitrogen_avg'] = soilnitrogenAvg;
|
||||||
|
data['soilphosphorus_avg'] = soilphosphorusAvg;
|
||||||
|
data['soilpotassium_avg'] = soilpotassiumAvg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Npk2 {
|
||||||
|
int? hour;
|
||||||
|
num? soiltemperatureAvg;
|
||||||
|
num? soilhumidityAvg;
|
||||||
|
num? soilconductivityAvg;
|
||||||
|
num? soilphAvg;
|
||||||
|
num? soilnitrogenAvg;
|
||||||
|
num? soilphosphorusAvg;
|
||||||
|
num? soilpotassiumAvg;
|
||||||
|
|
||||||
|
Npk2(
|
||||||
|
{this.hour,
|
||||||
|
this.soiltemperatureAvg,
|
||||||
|
this.soilhumidityAvg,
|
||||||
|
this.soilconductivityAvg,
|
||||||
|
this.soilphAvg,
|
||||||
|
this.soilnitrogenAvg,
|
||||||
|
this.soilphosphorusAvg,
|
||||||
|
this.soilpotassiumAvg});
|
||||||
|
|
||||||
|
Npk2.fromJson(Map<String, dynamic> json) {
|
||||||
|
hour = json['hour'];
|
||||||
|
soiltemperatureAvg = json['soiltemperature_avg'];
|
||||||
|
soilhumidityAvg = json['soilhumidity_avg'];
|
||||||
|
soilconductivityAvg = json['soilconductivity_avg'];
|
||||||
|
soilphAvg = json['soilph_avg'];
|
||||||
|
soilnitrogenAvg = json['soilnitrogen_avg'];
|
||||||
|
soilphosphorusAvg = json['soilphosphorus_avg'];
|
||||||
|
soilpotassiumAvg = json['soilpotassium_avg'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['hour'] = hour;
|
||||||
|
data['soiltemperature_avg'] = soiltemperatureAvg;
|
||||||
|
data['soilhumidity_avg'] = soilhumidityAvg;
|
||||||
|
data['soilconductivity_avg'] = soilconductivityAvg;
|
||||||
|
data['soilph_avg'] = soilphAvg;
|
||||||
|
data['soilnitrogen_avg'] = soilnitrogenAvg;
|
||||||
|
data['soilphosphorus_avg'] = soilphosphorusAvg;
|
||||||
|
data['soilpotassium_avg'] = soilpotassiumAvg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
class Npk1GraphicResponse {
|
||||||
|
DataNpk1? data;
|
||||||
|
int? statusCode;
|
||||||
|
String? message;
|
||||||
|
|
||||||
|
Npk1GraphicResponse({this.data, this.statusCode, this.message});
|
||||||
|
|
||||||
|
Npk1GraphicResponse.fromJson(Map<String, dynamic> json) {
|
||||||
|
data = json['data'] != null ? DataNpk1.fromJson(json['data']) : null;
|
||||||
|
statusCode = json['statusCode'];
|
||||||
|
message = json['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (this.data != null) {
|
||||||
|
data['data'] = this.data!.toJson();
|
||||||
|
}
|
||||||
|
data['statusCode'] = statusCode;
|
||||||
|
data['message'] = message;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataNpk1 {
|
||||||
|
List<Npk1>? npk1;
|
||||||
|
|
||||||
|
DataNpk1({this.npk1});
|
||||||
|
|
||||||
|
DataNpk1.fromJson(Map<String, dynamic> json) {
|
||||||
|
if (json['npk1'] != null) {
|
||||||
|
npk1 = <Npk1>[];
|
||||||
|
json['npk1'].forEach((v) {
|
||||||
|
npk1!.add(Npk1.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (npk1 != null) {
|
||||||
|
data['npk1'] = npk1!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Npk1 {
|
||||||
|
int? hour;
|
||||||
|
double? soiltemperatureAvg;
|
||||||
|
double? soilhumidityAvg;
|
||||||
|
double? soilconductivityAvg;
|
||||||
|
double? soilphAvg;
|
||||||
|
double? soilnitrogenAvg;
|
||||||
|
double? soilphosphorusAvg;
|
||||||
|
double? soilpotassiumAvg;
|
||||||
|
|
||||||
|
Npk1(
|
||||||
|
{this.hour,
|
||||||
|
this.soiltemperatureAvg,
|
||||||
|
this.soilhumidityAvg,
|
||||||
|
this.soilconductivityAvg,
|
||||||
|
this.soilphAvg,
|
||||||
|
this.soilnitrogenAvg,
|
||||||
|
this.soilphosphorusAvg,
|
||||||
|
this.soilpotassiumAvg});
|
||||||
|
|
||||||
|
Npk1.fromJson(Map<String, dynamic> json) {
|
||||||
|
hour = json['hour'];
|
||||||
|
soiltemperatureAvg = json['soiltemperature_avg'];
|
||||||
|
soilhumidityAvg = json['soilhumidity_avg'];
|
||||||
|
soilconductivityAvg = json['soilconductivity_avg'];
|
||||||
|
soilphAvg = json['soilph_avg'];
|
||||||
|
soilnitrogenAvg = json['soilnitrogen_avg'];
|
||||||
|
soilphosphorusAvg = json['soilphosphorus_avg'];
|
||||||
|
soilpotassiumAvg = json['soilpotassium_avg'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['hour'] = hour;
|
||||||
|
data['soiltemperature_avg'] = soiltemperatureAvg;
|
||||||
|
data['soilhumidity_avg'] = soilhumidityAvg;
|
||||||
|
data['soilconductivity_avg'] = soilconductivityAvg;
|
||||||
|
data['soilph_avg'] = soilphAvg;
|
||||||
|
data['soilnitrogen_avg'] = soilnitrogenAvg;
|
||||||
|
data['soilphosphorus_avg'] = soilphosphorusAvg;
|
||||||
|
data['soilpotassium_avg'] = soilpotassiumAvg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
class Npk1SoilTempGrafik {
|
||||||
|
Data? data;
|
||||||
|
int? statusCode;
|
||||||
|
String? message;
|
||||||
|
|
||||||
|
Npk1SoilTempGrafik({this.data, this.statusCode, this.message});
|
||||||
|
|
||||||
|
Npk1SoilTempGrafik.fromJson(Map<String, dynamic> json) {
|
||||||
|
data = json['data'] != null ? Data.fromJson(json['data']) : null;
|
||||||
|
statusCode = json['statusCode'];
|
||||||
|
message = json['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (this.data != null) {
|
||||||
|
data['data'] = this.data!.toJson();
|
||||||
|
}
|
||||||
|
data['statusCode'] = statusCode;
|
||||||
|
data['message'] = message;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Data {
|
||||||
|
List<Npk1>? npk1;
|
||||||
|
|
||||||
|
Data({this.npk1});
|
||||||
|
|
||||||
|
Data.fromJson(Map<String, dynamic> json) {
|
||||||
|
if (json['npk1'] != null) {
|
||||||
|
npk1 = <Npk1>[];
|
||||||
|
json['npk1'].forEach((v) {
|
||||||
|
npk1!.add(Npk1.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (npk1 != null) {
|
||||||
|
data['npk1'] = npk1!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Npk1 {
|
||||||
|
num? hour;
|
||||||
|
num? soiltemperatureAvg;
|
||||||
|
|
||||||
|
Npk1({this.hour, this.soiltemperatureAvg});
|
||||||
|
|
||||||
|
Npk1.fromJson(Map<String, dynamic> json) {
|
||||||
|
hour = json['hour'];
|
||||||
|
soiltemperatureAvg = json['soiltemperature_avg'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['hour'] = hour;
|
||||||
|
data['soiltemperature_avg'] = soiltemperatureAvg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
class Npk2GraphicResponse {
|
||||||
|
DataNpk2? data;
|
||||||
|
int? statusCode;
|
||||||
|
String? message;
|
||||||
|
|
||||||
|
Npk2GraphicResponse({this.data, this.statusCode, this.message});
|
||||||
|
|
||||||
|
Npk2GraphicResponse.fromJson(Map<String, dynamic> json) {
|
||||||
|
data = json['data'] != null ? DataNpk2.fromJson(json['data']) : null;
|
||||||
|
statusCode = json['statusCode'];
|
||||||
|
message = json['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (this.data != null) {
|
||||||
|
data['data'] = this.data!.toJson();
|
||||||
|
}
|
||||||
|
data['statusCode'] = statusCode;
|
||||||
|
data['message'] = message;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataNpk2 {
|
||||||
|
List<Npk2>? npk2;
|
||||||
|
|
||||||
|
DataNpk2({this.npk2});
|
||||||
|
|
||||||
|
DataNpk2.fromJson(Map<String, dynamic> json) {
|
||||||
|
if (json['npk2'] != null) {
|
||||||
|
npk2 = <Npk2>[];
|
||||||
|
json['npk2'].forEach((v) {
|
||||||
|
npk2!.add(Npk2.fromJson(v));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
if (npk2 != null) {
|
||||||
|
data['npk2'] = npk2!.map((v) => v.toJson()).toList();
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Npk2 {
|
||||||
|
int? hour;
|
||||||
|
double? soiltemperatureAvg;
|
||||||
|
double? soilhumidityAvg;
|
||||||
|
double? soilconductivityAvg;
|
||||||
|
double? soilphAvg;
|
||||||
|
double? soilnitrogenAvg;
|
||||||
|
double? soilphosphorusAvg;
|
||||||
|
double? soilpotassiumAvg;
|
||||||
|
|
||||||
|
Npk2(
|
||||||
|
{this.hour,
|
||||||
|
this.soiltemperatureAvg,
|
||||||
|
this.soilhumidityAvg,
|
||||||
|
this.soilconductivityAvg,
|
||||||
|
this.soilphAvg,
|
||||||
|
this.soilnitrogenAvg,
|
||||||
|
this.soilphosphorusAvg,
|
||||||
|
this.soilpotassiumAvg});
|
||||||
|
|
||||||
|
Npk2.fromJson(Map<String, dynamic> json) {
|
||||||
|
hour = json['hour'];
|
||||||
|
soiltemperatureAvg = json['soiltemperature_avg'];
|
||||||
|
soilhumidityAvg = json['soilhumidity_avg'];
|
||||||
|
soilconductivityAvg = json['soilconductivity_avg'];
|
||||||
|
soilphAvg = json['soilph_avg'];
|
||||||
|
soilnitrogenAvg = json['soilnitrogen_avg'];
|
||||||
|
soilphosphorusAvg = json['soilphosphorus_avg'];
|
||||||
|
soilpotassiumAvg = json['soilpotassium_avg'];
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
|
data['hour'] = hour;
|
||||||
|
data['soiltemperature_avg'] = soiltemperatureAvg;
|
||||||
|
data['soilhumidity_avg'] = soilhumidityAvg;
|
||||||
|
data['soilconductivity_avg'] = soilconductivityAvg;
|
||||||
|
data['soilph_avg'] = soilphAvg;
|
||||||
|
data['soilnitrogen_avg'] = soilnitrogenAvg;
|
||||||
|
data['soilphosphorus_avg'] = soilphosphorusAvg;
|
||||||
|
data['soilpotassium_avg'] = soilpotassiumAvg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -54,7 +54,7 @@ class HumidityScreen extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
const Icon(BootstrapIcons.droplet_half,
|
const Icon(BootstrapIcons.droplet_half,
|
||||||
size: 32, color: Colors.blue),
|
size: 32, color: Colors.blue),
|
||||||
Text('60 %', style: AppTheme.headline1),
|
Text('$humidity %', style: AppTheme.headline1),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -63,7 +63,7 @@ class HumidityScreen extends StatelessWidget {
|
||||||
child: AnimatedRadialGauge(
|
child: AnimatedRadialGauge(
|
||||||
duration: const Duration(seconds: 3),
|
duration: const Duration(seconds: 3),
|
||||||
curve: Curves.easeOut,
|
curve: Curves.easeOut,
|
||||||
value: 60,
|
value: humidity,
|
||||||
axis: GaugeAxis(
|
axis: GaugeAxis(
|
||||||
degrees: 360,
|
degrees: 360,
|
||||||
min: 0,
|
min: 0,
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class SoilMoistureScreen extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
const Icon(BootstrapIcons.water,
|
const Icon(BootstrapIcons.water,
|
||||||
size: 32, color: Colors.blue),
|
size: 32, color: Colors.blue),
|
||||||
Text('60 %', style: AppTheme.headline1),
|
Text('$moisture %', style: AppTheme.headline1),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
import 'package:agrilink_vocpro/core/state/result_state.dart';
|
||||||
|
import 'package:agrilink_vocpro/features/home/model/npk1_soil_temp_grafik.dart';
|
||||||
|
import 'package:agrilink_vocpro/features/home/service/home_service.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SoilTempProvider extends ChangeNotifier {
|
||||||
|
SoilTempProvider() {
|
||||||
|
getSoilTempData();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Npk1> dataFetched = [];
|
||||||
|
|
||||||
|
void setSoilTempData(List<Npk1> data) {
|
||||||
|
dataFetched = data;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultState dataState = ResultState.initial;
|
||||||
|
|
||||||
|
Future<void> getSoilTempData() async {
|
||||||
|
dataState = ResultState.loading;
|
||||||
|
notifyListeners();
|
||||||
|
try {
|
||||||
|
final result = await HomeService().getNpk1SoilTempGrafik();
|
||||||
|
if (result.data == null || result.data!.npk1!.isEmpty) {
|
||||||
|
dataState = ResultState.noData;
|
||||||
|
notifyListeners();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
setSoilTempData(result.data?.npk1 ?? []);
|
||||||
|
dataState = ResultState.hasData;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Error: $e');
|
||||||
|
dataState = ResultState.error;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
dataState = ResultState.initial;
|
||||||
|
dataFetched = [];
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
import 'package:agrilink_vocpro/core/constant/app_constant.dart';
|
import 'package:agrilink_vocpro/core/constant/app_constant.dart';
|
||||||
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
|
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
|
||||||
|
import 'package:agrilink_vocpro/core/state/result_state.dart';
|
||||||
import 'package:agrilink_vocpro/core/widgets/show_info.dart';
|
import 'package:agrilink_vocpro/core/widgets/show_info.dart';
|
||||||
|
import 'package:agrilink_vocpro/features/home/pages/soil_temperature/provider/soil_temp_provider.dart';
|
||||||
import 'package:agrilink_vocpro/features/home/widgets/graphic_widget.dart';
|
import 'package:agrilink_vocpro/features/home/widgets/graphic_widget.dart';
|
||||||
import 'package:bootstrap_icons/bootstrap_icons.dart';
|
import 'package:bootstrap_icons/bootstrap_icons.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
import 'package:gauge_indicator/gauge_indicator.dart';
|
import 'package:gauge_indicator/gauge_indicator.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class SoilTemperatureScreen extends StatelessWidget {
|
class SoilTemperatureScreen extends StatelessWidget {
|
||||||
const SoilTemperatureScreen({super.key, this.temperature = 0});
|
const SoilTemperatureScreen({super.key, this.temperature = 0});
|
||||||
|
|
@ -15,7 +18,9 @@ class SoilTemperatureScreen extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return ChangeNotifierProvider(
|
||||||
|
create: (context) => SoilTempProvider(),
|
||||||
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Soil Temperature', style: AppTheme.labelMedium),
|
title: Text('Soil Temperature', style: AppTheme.labelMedium),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
|
|
@ -53,7 +58,7 @@ class SoilTemperatureScreen extends StatelessWidget {
|
||||||
const Icon(BootstrapIcons.water,
|
const Icon(BootstrapIcons.water,
|
||||||
size: 32, color: Colors.green),
|
size: 32, color: Colors.green),
|
||||||
Text(
|
Text(
|
||||||
'${value.toStringAsFixed(0)}°C', // Animated percentage text
|
'$value°C', // Animated percentage text
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|
@ -129,11 +134,6 @@ class SoilTemperatureScreen extends StatelessWidget {
|
||||||
Text('Low',
|
Text('Low',
|
||||||
style: AppTheme.labelMedium
|
style: AppTheme.labelMedium
|
||||||
.copyWith(color: Colors.blue)),
|
.copyWith(color: Colors.blue)),
|
||||||
// SizedBox(height: 8.h),
|
|
||||||
// const Icon(
|
|
||||||
// BootstrapIcons.thermometer_low,
|
|
||||||
// color: Colors.blue,
|
|
||||||
// ),
|
|
||||||
SizedBox(height: 8.h),
|
SizedBox(height: 8.h),
|
||||||
Text(
|
Text(
|
||||||
'<20°C',
|
'<20°C',
|
||||||
|
|
@ -191,11 +191,6 @@ class SoilTemperatureScreen extends StatelessWidget {
|
||||||
Text('high',
|
Text('high',
|
||||||
style: AppTheme.labelMedium
|
style: AppTheme.labelMedium
|
||||||
.copyWith(color: Colors.orange)),
|
.copyWith(color: Colors.orange)),
|
||||||
// SizedBox(height: 8.h),
|
|
||||||
// const Icon(
|
|
||||||
// BootstrapIcons.thermometer_high,
|
|
||||||
// color: Colors.orange,
|
|
||||||
// ),
|
|
||||||
SizedBox(height: 8.h),
|
SizedBox(height: 8.h),
|
||||||
Text(
|
Text(
|
||||||
'>30°C',
|
'>30°C',
|
||||||
|
|
@ -218,17 +213,76 @@ class SoilTemperatureScreen extends StatelessWidget {
|
||||||
borderRadius: BorderRadius.circular(16.w),
|
borderRadius: BorderRadius.circular(16.w),
|
||||||
border: Border.all(color: Colors.grey.shade300, width: 1.w),
|
border: Border.all(color: Colors.grey.shade300, width: 1.w),
|
||||||
),
|
),
|
||||||
child: const GarphicWidget(
|
child: Consumer<SoilTempProvider>(
|
||||||
gradientColors: [
|
builder: (context, provider, child) {
|
||||||
|
switch (provider.dataState) {
|
||||||
|
case ResultState.loading:
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
case ResultState.hasData:
|
||||||
|
return GarphicWidget(
|
||||||
|
gradientColors: const [
|
||||||
Colors.cyan,
|
Colors.cyan,
|
||||||
Colors.amber,
|
Colors.amber,
|
||||||
],
|
],
|
||||||
|
hour: List.generate(provider.dataFetched.length,
|
||||||
|
(index) => provider.dataFetched[index].hour ?? 0),
|
||||||
|
data: List.generate(
|
||||||
|
provider.dataFetched.length,
|
||||||
|
(index) =>
|
||||||
|
provider.dataFetched[index].soiltemperatureAvg
|
||||||
|
?.toDouble() ??
|
||||||
|
0),
|
||||||
|
);
|
||||||
|
case ResultState.error:
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
BootstrapIcons.exclamation_circle,
|
||||||
|
color: Colors.grey.shade400,
|
||||||
),
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
Text(
|
||||||
|
'Terjadi Kesalahan',
|
||||||
|
style: AppTheme.labelSmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
case ResultState.noData:
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
BootstrapIcons.database_fill_x,
|
||||||
|
color: Colors.grey.shade400,
|
||||||
|
),
|
||||||
|
SizedBox(height: 8.h),
|
||||||
|
Text(
|
||||||
|
'Tidak Ada Data',
|
||||||
|
style: AppTheme.labelSmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
case ResultState.initial:
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
default:
|
||||||
|
return const Center(
|
||||||
|
child: Text('Default Error'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,101 @@
|
||||||
import 'package:agrilink_vocpro/core/state/result_state.dart';
|
import 'package:agrilink_vocpro/core/state/result_state.dart';
|
||||||
|
import 'package:agrilink_vocpro/domain/service/app_service.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class HomeProvider extends ChangeNotifier {
|
class HomeProvider extends ChangeNotifier {
|
||||||
final DateTime currentDate = DateTime.now();
|
final DateTime currentDate = DateTime.now();
|
||||||
|
|
||||||
|
num _dhtHumidity = 0;
|
||||||
|
num get dhtHumidity => _dhtHumidity;
|
||||||
|
|
||||||
|
num _dhtTemperature = 0;
|
||||||
|
num get dhtTemperature => _dhtTemperature;
|
||||||
|
|
||||||
|
num _dhtLuminosity = 0;
|
||||||
|
num get dhtLuminosity => _dhtLuminosity;
|
||||||
|
|
||||||
|
num _npk1SoilMoisture = 0;
|
||||||
|
num get npk1SoilMoisture => _npk1SoilMoisture;
|
||||||
|
|
||||||
|
num _npk1Temperature = 0;
|
||||||
|
num get npk1Temperature => _npk1Temperature;
|
||||||
|
|
||||||
|
num _npk1SoilPh = 0;
|
||||||
|
num get npk1SoilPh => _npk1SoilPh;
|
||||||
|
|
||||||
|
num _npk1SoilEc = 0;
|
||||||
|
num get npk1SoilEc => _npk1SoilEc;
|
||||||
|
|
||||||
|
num _npk1SoilNitrogen = 0;
|
||||||
|
num get npk1SoilNitrogen => _npk1SoilNitrogen;
|
||||||
|
|
||||||
|
num _npk1SoilPhosphorus = 0;
|
||||||
|
num get npk1SoilPhosphorus => _npk1SoilPhosphorus;
|
||||||
|
|
||||||
|
num _npk1SoilPotassium = 0;
|
||||||
|
num get npk1SoilPotassium => _npk1SoilPotassium;
|
||||||
|
|
||||||
|
num _npk2SoilMoisture = 0;
|
||||||
|
num get npk2SoilMoisture => _npk2SoilMoisture;
|
||||||
|
|
||||||
|
num _npk2Temperature = 0;
|
||||||
|
num get npk2Temperature => _npk2Temperature;
|
||||||
|
|
||||||
|
num _npk2SoilPh = 0;
|
||||||
|
num get npk2SoilPh => _npk2SoilPh;
|
||||||
|
|
||||||
|
num _npk2SoilEc = 0;
|
||||||
|
num get npk2SoilEc => _npk2SoilEc;
|
||||||
|
|
||||||
|
num _npk2SoilNitrogen = 0;
|
||||||
|
num get npk2SoilNitrogen => _npk2SoilNitrogen;
|
||||||
|
|
||||||
|
num _npk2SoilPhosphorus = 0;
|
||||||
|
num get npk2SoilPhosphorus => _npk2SoilPhosphorus;
|
||||||
|
|
||||||
|
num _npk2SoilPotassium = 0;
|
||||||
|
num get npk2SoilPotassium => _npk2SoilPotassium;
|
||||||
|
|
||||||
HomeProvider() {
|
HomeProvider() {
|
||||||
getData();
|
getLatestData();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultState dataState = ResultState.initial;
|
ResultState dataState = ResultState.initial;
|
||||||
|
|
||||||
Future<void> getData() async {
|
Future<void> getLatestData() async {
|
||||||
dataState = ResultState.loading;
|
dataState = ResultState.loading;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
try {
|
try {
|
||||||
print('Fetching data...');
|
final result = await AppService().getLatestData();
|
||||||
await Future.delayed(const Duration(seconds: 3));
|
if (result.data == null) {
|
||||||
print('Data fetched');
|
dataState = ResultState.noData;
|
||||||
|
notifyListeners();
|
||||||
|
} else {
|
||||||
|
final data = result.data!;
|
||||||
|
_dhtHumidity = data.dht?[0].vicihumidityAvg ?? 0;
|
||||||
|
_dhtTemperature = data.dht?[0].vicitemperatureAvg ?? 0;
|
||||||
|
_dhtLuminosity = data.dht?[0].viciluminosityAvg ?? 0;
|
||||||
|
|
||||||
|
_npk1SoilMoisture = data.npk1?[0].soilhumidityAvg ?? 0;
|
||||||
|
_npk1Temperature = data.npk1?[0].soiltemperatureAvg ?? 0;
|
||||||
|
_npk1SoilPh = data.npk1?[0].soilphAvg ?? 0;
|
||||||
|
_npk1SoilEc = data.npk1?[0].soilconductivityAvg ?? 0;
|
||||||
|
_npk1SoilNitrogen = data.npk1?[0].soilnitrogenAvg ?? 0;
|
||||||
|
_npk1SoilPhosphorus = data.npk1?[0].soilphosphorusAvg ?? 0;
|
||||||
|
_npk1SoilPotassium = data.npk1?[0].soilpotassiumAvg ?? 0;
|
||||||
|
|
||||||
|
_npk2SoilMoisture = data.npk2?[0].soilhumidityAvg ?? 0;
|
||||||
|
_npk2Temperature = data.npk2?[0].soiltemperatureAvg ?? 0;
|
||||||
|
_npk2SoilPh = data.npk2?[0].soilphAvg ?? 0;
|
||||||
|
_npk2SoilEc = data.npk2?[0].soilconductivityAvg ?? 0;
|
||||||
|
_npk2SoilNitrogen = data.npk2?[0].soilnitrogenAvg ?? 0;
|
||||||
|
_npk2SoilPhosphorus = data.npk2?[0].soilphosphorusAvg ?? 0;
|
||||||
|
_npk2SoilPotassium = data.npk2?[0].soilpotassiumAvg ?? 0;
|
||||||
dataState = ResultState.hasData;
|
dataState = ResultState.hasData;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
print('Error: $e');
|
||||||
dataState = ResultState.error;
|
dataState = ResultState.error;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
@ -31,57 +107,3 @@ class HomeProvider extends ChangeNotifier {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// List<CensorDataRule> humidtyRules = [
|
|
||||||
// CensorDataRule(
|
|
||||||
// minPercentage: 0,
|
|
||||||
// maxPercentage: 30,
|
|
||||||
// censorText: 'Very Low',
|
|
||||||
// description:
|
|
||||||
// 'Udara sangat kering. Tanaman bisa mengalami stress akibat kekurangan air.',
|
|
||||||
// action:
|
|
||||||
// 'Aktifkan sistem penyiraman atau humidifier untuk menaikkan kelembaban. Periksa juga apakah ada kebocoran pada sistem irigasi yang mengakibatkan kelembaban terlalu rendah.',
|
|
||||||
// color: Colors.red,
|
|
||||||
// ),
|
|
||||||
// CensorDataRule(
|
|
||||||
// minPercentage: 31,
|
|
||||||
// maxPercentage: 50,
|
|
||||||
// censorText: 'Low',
|
|
||||||
// description:
|
|
||||||
// 'Kelembaban masih cukup rendah. Beberapa jenis tanaman mungkin sudah mulai terpengaruh.',
|
|
||||||
// action:
|
|
||||||
// 'Pertimbangkan untuk menambah irigasi atau memperpanjang durasi penyiraman. Pantau tanaman secara berkala.',
|
|
||||||
// color: Colors.orange,
|
|
||||||
// ),
|
|
||||||
// CensorDataRule(
|
|
||||||
// minPercentage: 51,
|
|
||||||
// maxPercentage: 70,
|
|
||||||
// censorText: 'Normal',
|
|
||||||
// description:
|
|
||||||
// 'Ini adalah kelembaban yang ideal untuk sebagian besar tanaman dalam greenhouse.',
|
|
||||||
// action:
|
|
||||||
// 'Pertahankan kondisi ini. Tidak ada tindakan yang diperlukan kecuali jika ada perubahan mendadak.',
|
|
||||||
// color: Colors.green,
|
|
||||||
// ),
|
|
||||||
// CensorDataRule(
|
|
||||||
// minPercentage: 71,
|
|
||||||
// maxPercentage: 85,
|
|
||||||
// censorText: 'High',
|
|
||||||
// description:
|
|
||||||
// 'Udara mulai terlalu lembap. Kelembaban tinggi dapat meningkatkan risiko penyakit jamur atau bakteri.',
|
|
||||||
// action:
|
|
||||||
// 'Aktifkan ventilasi atau kipas untuk mengurangi kelembaban. Pastikan aliran udara di greenhouse cukup baik.',
|
|
||||||
// color: Colors.lime,
|
|
||||||
// ),
|
|
||||||
// CensorDataRule(
|
|
||||||
// minPercentage: 86,
|
|
||||||
// maxPercentage: 100,
|
|
||||||
// censorText: 'Very High',
|
|
||||||
// description:
|
|
||||||
// 'Udara sangat lembap, yang bisa berisiko menyebabkan jamur, lumut, dan penyakit tanaman.',
|
|
||||||
// action:
|
|
||||||
// 'Segera aktifkan sistem ventilasi maksimal, mungkin juga gunakan dehumidifier jika diperlukan. Kurangi frekuensi penyiraman atau periksa sistem irigasi agar tidak berlebihan.',
|
|
||||||
// color: Colors.brown,
|
|
||||||
// ),
|
|
||||||
// ];
|
|
||||||
|
|
|
||||||
29
agrilink_vocpro/lib/features/home/service/home_service.dart
Normal file
29
agrilink_vocpro/lib/features/home/service/home_service.dart
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import 'package:agrilink_vocpro/core/constant/app_constant.dart';
|
||||||
|
import 'package:agrilink_vocpro/features/home/model/npk1_soil_temp_grafik.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
class HomeService {
|
||||||
|
final Dio _dioWithoutInterceptor = Dio(
|
||||||
|
BaseOptions(
|
||||||
|
baseUrl: AppConstant.baseUrl,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<Npk1SoilTempGrafik> getNpk1SoilTempGrafik() async {
|
||||||
|
try {
|
||||||
|
final result = await _dioWithoutInterceptor.get(
|
||||||
|
'/sensor/getData?metric=soilTemperature&range[start]=2024-10-03&range[end]=2024-10-03&range[time_range]=HOURLY&sensor=npk1',
|
||||||
|
);
|
||||||
|
if (result.statusCode == 200) {
|
||||||
|
print(result.data.toString());
|
||||||
|
final data = Npk1SoilTempGrafik.fromJson(result.data);
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load data');
|
||||||
|
}
|
||||||
|
} on DioException catch (e) {
|
||||||
|
print(e);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -60,7 +60,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<HomeProvider>().getData();
|
context.read<HomeProvider>().getLatestData();
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.refresh_rounded,
|
Icons.refresh_rounded,
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,12 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||||
|
|
||||||
class GarphicWidget extends StatelessWidget {
|
class GarphicWidget extends StatelessWidget {
|
||||||
const GarphicWidget({super.key, required this.gradientColors});
|
const GarphicWidget(
|
||||||
|
{super.key, required this.gradientColors, this.data, this.hour});
|
||||||
|
|
||||||
final List<Color> gradientColors;
|
final List<Color> gradientColors;
|
||||||
|
final List<num>? hour;
|
||||||
|
final List<num>? data;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
|
|
@ -48,6 +50,16 @@ class GarphicWidget extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getMaxValue() {
|
||||||
|
int max = 0;
|
||||||
|
for (int i = 0; i < data!.length; i++) {
|
||||||
|
if (data![i] > max) {
|
||||||
|
max = data![i].toInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
LineChartData mainData() {
|
LineChartData mainData() {
|
||||||
return LineChartData(
|
return LineChartData(
|
||||||
gridData: const FlGridData(
|
gridData: const FlGridData(
|
||||||
|
|
@ -80,18 +92,16 @@ class GarphicWidget extends StatelessWidget {
|
||||||
minX: 0,
|
minX: 0,
|
||||||
maxX: 24,
|
maxX: 24,
|
||||||
minY: 0,
|
minY: 0,
|
||||||
maxY: 100,
|
maxY: data == null ? 0 : getMaxValue().toDouble(),
|
||||||
lineBarsData: [
|
lineBarsData: [
|
||||||
LineChartBarData(
|
LineChartBarData(
|
||||||
spots: const [
|
spots: data == null && hour == null
|
||||||
FlSpot(0, 38),
|
? [FlSpot(0, 0)]
|
||||||
FlSpot(1, 42),
|
: List.generate(
|
||||||
FlSpot(2, 50),
|
hour!.length,
|
||||||
FlSpot(3, 53),
|
(index) =>
|
||||||
FlSpot(4, 58),
|
FlSpot(hour![index].toDouble(), data![index].toDouble()),
|
||||||
FlSpot(5, 64),
|
),
|
||||||
FlSpot(7, 49),
|
|
||||||
],
|
|
||||||
isCurved: true,
|
isCurved: true,
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
colors: gradientColors,
|
colors: gradientColors,
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class ListDataFromCensorDht extends StatelessWidget {
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Humidity',
|
title: 'Humidity',
|
||||||
subtitle: 'kelembaban udara',
|
subtitle: 'kelembaban udara',
|
||||||
value: '60',
|
value: provider.dhtHumidity.toString(),
|
||||||
unit: '%',
|
unit: '%',
|
||||||
icon: BootstrapIcons.droplet_half,
|
icon: BootstrapIcons.droplet_half,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
|
|
@ -58,29 +58,32 @@ class ListDataFromCensorDht extends StatelessWidget {
|
||||||
iconColor: Colors.white,
|
iconColor: Colors.white,
|
||||||
censorIdentifier: 'NPK 1',
|
censorIdentifier: 'NPK 1',
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context.push('${AppRoute.humidity}/60');
|
await context
|
||||||
|
.push('${AppRoute.humidity}/${provider.dhtHumidity}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Temperature',
|
title: 'Temperature',
|
||||||
subtitle: 'suhu greenhouse',
|
subtitle: 'suhu greenhouse',
|
||||||
value: '43',
|
value: provider.dhtTemperature.toString(),
|
||||||
unit: '°C',
|
unit: '°C',
|
||||||
icon: BootstrapIcons.thermometer_half,
|
icon: BootstrapIcons.thermometer_half,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context.push('${AppRoute.temperature}/43');
|
await context.push(
|
||||||
|
'${AppRoute.temperature}/${provider.dhtTemperature}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Light',
|
title: 'Light',
|
||||||
subtitle: 'intensitas cahaya',
|
subtitle: 'intensitas cahaya',
|
||||||
value: '320.5',
|
value: provider.dhtLuminosity.toString(),
|
||||||
unit: 'lux',
|
unit: 'lux',
|
||||||
icon: BootstrapIcons.sun,
|
icon: BootstrapIcons.sun,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context.push('${AppRoute.light}/320.5');
|
await context
|
||||||
|
.push('${AppRoute.light}/${provider.dhtLuminosity}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class ListDataFromCensorNpk1 extends StatelessWidget {
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Temperature',
|
title: 'Temperature',
|
||||||
subtitle: 'Suhu tanah',
|
subtitle: 'Suhu tanah',
|
||||||
value: '28',
|
value: provider.npk1Temperature.toString(),
|
||||||
unit: '°C',
|
unit: '°C',
|
||||||
icon: BootstrapIcons.thermometer_half,
|
icon: BootstrapIcons.thermometer_half,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
|
|
@ -57,76 +57,82 @@ class ListDataFromCensorNpk1 extends StatelessWidget {
|
||||||
iconColor: Colors.white,
|
iconColor: Colors.white,
|
||||||
censorIdentifier: censorIdentifier,
|
censorIdentifier: censorIdentifier,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context.push('${AppRoute.soilTemperature}/28');
|
await context.push(
|
||||||
|
'${AppRoute.soilTemperature}/${provider.npk1Temperature}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Soil Moisture',
|
title: 'Soil Moisture',
|
||||||
subtitle: 'kelembaban tanah',
|
subtitle: 'kelembaban tanah',
|
||||||
value: '40',
|
value: provider.npk1SoilMoisture.toString(),
|
||||||
unit: '%',
|
unit: '%',
|
||||||
icon: Icons.water_outlined,
|
icon: Icons.water_outlined,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
censorIdentifier: censorIdentifier,
|
censorIdentifier: censorIdentifier,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context.push('${AppRoute.soilMoisture}/40');
|
await context.push(
|
||||||
|
'${AppRoute.soilMoisture}/${provider.npk1SoilMoisture}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Acid Level (PH)',
|
title: 'Acid Level (PH)',
|
||||||
subtitle: 'tingkat keasaman',
|
subtitle: 'tingkat keasaman',
|
||||||
value: '6.5',
|
value: provider.npk1SoilPh.toString(),
|
||||||
unit: 'pH',
|
unit: 'pH',
|
||||||
icon: BootstrapIcons.pie_chart,
|
icon: BootstrapIcons.pie_chart,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
censorIdentifier: censorIdentifier,
|
censorIdentifier: censorIdentifier,
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
context.push('${AppRoute.ph}/6.5');
|
context.push('${AppRoute.ph}/${provider.npk1SoilPh}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Conductivity',
|
title: 'Conductivity',
|
||||||
subtitle: 'Daya Arus Listrik',
|
subtitle: 'Daya Arus Listrik',
|
||||||
value: '234',
|
value: provider.npk1SoilEc.toString(),
|
||||||
unit: 'µS/cm',
|
unit: 'µS/cm',
|
||||||
icon: Icons.electric_bolt,
|
icon: Icons.electric_bolt,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
censorIdentifier: censorIdentifier,
|
censorIdentifier: censorIdentifier,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context.push('${AppRoute.conductivity}/234');
|
await context
|
||||||
|
.push('${AppRoute.conductivity}/${provider.npk1SoilEc}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Nitrogen',
|
title: 'Nitrogen',
|
||||||
subtitle: 'Kadar Nitrogen',
|
subtitle: 'Kadar Nitrogen',
|
||||||
value: '30',
|
value: provider.npk1SoilNitrogen.toString(),
|
||||||
unit: 'ppm',
|
unit: 'ppm',
|
||||||
icon: CupertinoIcons.eyedropper,
|
icon: CupertinoIcons.eyedropper,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context.push('${AppRoute.nitrogen}/30');
|
await context.push(
|
||||||
|
'${AppRoute.nitrogen}/${provider.npk1SoilNitrogen}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Potassium',
|
title: 'Potassium',
|
||||||
subtitle: 'Kadar kalium',
|
subtitle: 'Kadar kalium',
|
||||||
value: '20',
|
value: provider.npk1SoilPotassium.toString(),
|
||||||
unit: 'ppm',
|
unit: 'ppm',
|
||||||
icon: CupertinoIcons.eyedropper,
|
icon: CupertinoIcons.eyedropper,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context.push('${AppRoute.potassium}/20');
|
await context.push(
|
||||||
|
'${AppRoute.potassium}/${provider.npk1SoilPotassium}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Phosphorus',
|
title: 'Phosphorus',
|
||||||
subtitle: 'Kadar Fosfor',
|
subtitle: 'Kadar Fosfor',
|
||||||
value: '54',
|
value: provider.npk1SoilPhosphorus.toString(),
|
||||||
unit: 'ppm',
|
unit: 'ppm',
|
||||||
icon: CupertinoIcons.eyedropper,
|
icon: CupertinoIcons.eyedropper,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await context.push('${AppRoute.phosphorus}/54');
|
await context.push(
|
||||||
|
'${AppRoute.phosphorus}/${provider.npk1SoilPhosphorus}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import 'package:agrilink_vocpro/core/constant/app_color.dart';
|
import 'package:agrilink_vocpro/core/constant/app_color.dart';
|
||||||
import 'package:agrilink_vocpro/core/route/app_route.dart';
|
import 'package:agrilink_vocpro/core/route/app_route.dart';
|
||||||
import 'package:agrilink_vocpro/core/state/result_state.dart';
|
import 'package:agrilink_vocpro/core/state/result_state.dart';
|
||||||
import 'package:agrilink_vocpro/features/home/pages/soil_moisture/view/soil_moisture_screen.dart';
|
|
||||||
import 'package:agrilink_vocpro/features/home/pages/temperature/view/temperature_screen.dart';
|
|
||||||
import 'package:agrilink_vocpro/features/home/provider/home_provider.dart';
|
import 'package:agrilink_vocpro/features/home/provider/home_provider.dart';
|
||||||
import 'package:agrilink_vocpro/features/home/widgets/censor_item_loading_widgets.dart';
|
import 'package:agrilink_vocpro/features/home/widgets/censor_item_loading_widgets.dart';
|
||||||
import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart';
|
import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart';
|
||||||
|
|
@ -51,7 +49,7 @@ class ListDataFromCensorNpk2 extends StatelessWidget {
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Temperature',
|
title: 'Temperature',
|
||||||
subtitle: 'Suhu tanah',
|
subtitle: 'Suhu tanah',
|
||||||
value: '28',
|
value: provider.npk2Temperature.toString(),
|
||||||
unit: '°C',
|
unit: '°C',
|
||||||
icon: BootstrapIcons.thermometer_half,
|
icon: BootstrapIcons.thermometer_half,
|
||||||
textColor: Colors.white,
|
textColor: Colors.white,
|
||||||
|
|
@ -59,77 +57,83 @@ class ListDataFromCensorNpk2 extends StatelessWidget {
|
||||||
iconColor: Colors.white,
|
iconColor: Colors.white,
|
||||||
censorIdentifier: censorIdentifier,
|
censorIdentifier: censorIdentifier,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await Navigator.push(
|
await context.push(
|
||||||
context,
|
'${AppRoute.soilTemperature}/${provider.npk2Temperature}');
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const TemperatureScreen()));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Soil Moisture',
|
title: 'Soil Moisture',
|
||||||
subtitle: 'kelembaban tanah',
|
subtitle: 'kelembaban tanah',
|
||||||
value: '40',
|
value: provider.npk2SoilMoisture.toString(),
|
||||||
unit: '%',
|
unit: '%',
|
||||||
icon: Icons.water_outlined,
|
icon: Icons.water_outlined,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
censorIdentifier: censorIdentifier,
|
censorIdentifier: censorIdentifier,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await Navigator.push(
|
await context.push(
|
||||||
context,
|
'${AppRoute.soilMoisture}/${provider.npk2SoilMoisture}');
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const SoilMoistureScreen(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Acid Level (PH)',
|
title: 'Acid Level (PH)',
|
||||||
subtitle: 'tingkat keasaman',
|
subtitle: 'tingkat keasaman',
|
||||||
value: '6.5',
|
value: provider.npk2SoilPh.toString(),
|
||||||
unit: 'pH',
|
unit: 'pH',
|
||||||
icon: BootstrapIcons.pie_chart,
|
icon: BootstrapIcons.pie_chart,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
censorIdentifier: censorIdentifier,
|
censorIdentifier: censorIdentifier,
|
||||||
onTap: () {},
|
onTap: () async {
|
||||||
|
context.push('${AppRoute.ph}/${provider.npk2SoilPh}');
|
||||||
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Conductivity',
|
title: 'Conductivity',
|
||||||
subtitle: 'Daya Arus Listrik',
|
subtitle: 'Daya Arus Listrik',
|
||||||
value: '234',
|
value: provider.npk2SoilEc.toString(),
|
||||||
unit: 'µS/cm',
|
unit: 'µS/cm',
|
||||||
icon: Icons.electric_bolt,
|
icon: Icons.electric_bolt,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
censorIdentifier: censorIdentifier,
|
censorIdentifier: censorIdentifier,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
context.push(AppRoute.humidity, extra: '60');
|
await context
|
||||||
|
.push('${AppRoute.conductivity}/${provider.npk2SoilEc}');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Nitrogen',
|
title: 'Nitrogen',
|
||||||
subtitle: 'Kadar Nitrogen',
|
subtitle: 'Kadar Nitrogen',
|
||||||
value: '30',
|
value: provider.npk2SoilNitrogen.toString(),
|
||||||
unit: 'ppm',
|
unit: 'ppm',
|
||||||
icon: CupertinoIcons.eyedropper,
|
icon: CupertinoIcons.eyedropper,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
onTap: () {},
|
onTap: () async {
|
||||||
|
await context.push(
|
||||||
|
'${AppRoute.nitrogen}/${provider.npk2SoilNitrogen}');
|
||||||
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Potassium',
|
title: 'Potassium',
|
||||||
subtitle: 'Kadar kalium',
|
subtitle: 'Kadar kalium',
|
||||||
value: '20',
|
value: provider.npk2SoilPotassium.toString(),
|
||||||
unit: 'ppm',
|
unit: 'ppm',
|
||||||
icon: CupertinoIcons.eyedropper,
|
icon: CupertinoIcons.eyedropper,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
onTap: () {},
|
onTap: () async {
|
||||||
|
await context.push(
|
||||||
|
'${AppRoute.potassium}/${provider.npk2SoilPotassium}');
|
||||||
|
},
|
||||||
),
|
),
|
||||||
DataDisplayerWidget(
|
DataDisplayerWidget(
|
||||||
title: 'Phosphorus',
|
title: 'Phosphorus',
|
||||||
subtitle: 'Kadar Fosfor',
|
subtitle: 'Kadar Fosfor',
|
||||||
value: '54',
|
value: provider.npk2SoilPhosphorus.toString(),
|
||||||
unit: 'ppm',
|
unit: 'ppm',
|
||||||
icon: CupertinoIcons.eyedropper,
|
icon: CupertinoIcons.eyedropper,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
onTap: () {},
|
onTap: () async {
|
||||||
|
await context.push(
|
||||||
|
'${AppRoute.phosphorus}/${provider.npk2SoilPhosphorus}');
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -141,10 +141,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: file
|
name: file
|
||||||
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.0"
|
version: "7.0.1"
|
||||||
fl_chart:
|
fl_chart:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -162,10 +162,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: flutter_lints
|
name: flutter_lints
|
||||||
sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
|
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "5.0.0"
|
||||||
flutter_screenutil:
|
flutter_screenutil:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -196,10 +196,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: "2ddb88e9ad56ae15ee144ed10e33886777eb5ca2509a914850a5faa7b52ff459"
|
sha256: "6f1b756f6e863259a99135ff3c95026c3cdca17d10ebef2bba2261a25ddc8bbc"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.2.7"
|
version: "14.3.0"
|
||||||
google_fonts:
|
google_fonts:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -268,10 +268,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: lints
|
name: lints
|
||||||
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
|
sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "5.0.0"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -340,10 +340,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7"
|
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.10"
|
version: "2.2.12"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -412,18 +412,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e"
|
sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.2"
|
version: "2.3.3"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_foundation
|
name: shared_preferences_foundation
|
||||||
sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
|
sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.2"
|
version: "2.5.3"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -561,18 +561,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
|
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.1.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.1.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.5.1 <4.0.0"
|
dart: ">=3.5.1 <4.0.0"
|
||||||
flutter: ">=3.22.0"
|
flutter: ">=3.24.0"
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ dev_dependencies:
|
||||||
# activated in the `analysis_options.yaml` file located at the root of your
|
# activated in the `analysis_options.yaml` file located at the root of your
|
||||||
# package. See that file for information about deactivating specific lint
|
# package. See that file for information about deactivating specific lint
|
||||||
# rules and activating additional ones.
|
# rules and activating additional ones.
|
||||||
flutter_lints: ^4.0.0
|
flutter_lints: ^5.0.0
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user