fix: fixing the grafik UI for sensor data

This commit is contained in:
Syaroful 2024-10-09 08:21:10 +07:00
parent fc4350f1dd
commit 04769c4f00
19 changed files with 530 additions and 325 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -2,7 +2,7 @@ class AppConstant {
static const String appName = 'Kebun Pintar';
static const String appVersion = '1.0.0';
static const String baseUrl = 'https://agrilinkvocpropisdev.id/api/v1';
static const String baseUrl = 'http://192.168.11.41:3333/api/';
static const String mqttServer = 'armadillo.rmq.cloudamqp.com';
static const String mqttUsername = 'obyskxhx:obyskxhx';

View File

@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
Future<dynamic> showInfo(BuildContext context, String title, String content) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(title),
const SizedBox(height: 16),
Text(
style: Theme.of(context).textTheme.bodySmall,
content,
),
],
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('OK'),
)
],
),
);
}

View File

@ -0,0 +1,66 @@
class RelayResponse {
bool? success;
List<Relay>? data;
RelayResponse({this.success, this.data});
RelayResponse.fromJson(Map<String, dynamic> json) {
success = json['success'];
if (json['data'] != null) {
data = <Relay>[];
json['data'].forEach((v) {
data!.add(Relay.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['success'] = success;
if (this.data != null) {
data['data'] = this.data!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Relay {
int? id;
int? number;
String? enabledAt;
String? disabledAt;
bool? currentStatus;
String? createdAt;
String? updatedAt;
Relay(
{this.id,
this.number,
this.enabledAt,
this.disabledAt,
this.currentStatus,
this.createdAt,
this.updatedAt});
Relay.fromJson(Map<String, dynamic> json) {
id = json['id'];
number = json['number'];
enabledAt = json['enabled_at'];
disabledAt = json['disabled_at'];
currentStatus = json['current_status'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['number'] = number;
data['enabled_at'] = enabledAt;
data['disabled_at'] = disabledAt;
data['current_status'] = currentStatus;
data['created_at'] = createdAt;
data['updated_at'] = updatedAt;
return data;
}
}

View File

@ -1,4 +1,5 @@
import 'package:agrilink_vocpro/core/constant/app_contant.dart';
import 'package:agrilink_vocpro/core/constant/app_constant.dart';
import 'package:agrilink_vocpro/data/model/relay_response.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
@ -9,8 +10,17 @@ class AppService {
),
);
Future<void> getGreenHouseData() async {
try {} on DioException catch (e) {
Future<RelayResponse> getRelayStatus() async {
try {
await Future.delayed(const Duration(seconds: 3));
final result = await _dioWithoutInterceptor.get('get-relay');
if (result.statusCode == 200) {
final data = RelayResponse.fromJson(result.data);
return data;
} else {
throw Exception('Failed to load data');
}
} on DioException catch (e) {
if (kDebugMode) {
print(e);
}

View File

@ -1,86 +1,125 @@
import 'dart:math';
import 'package:agrilink_vocpro/core/state/result_state.dart';
import 'package:agrilink_vocpro/domain/service/mqtt_service.dart';
import 'package:agrilink_vocpro/domain/service/app_service.dart';
import 'package:flutter/material.dart';
class ControlProvider extends ChangeNotifier {
final MQTTService _mqttService = MQTTService();
final AppService _appService = AppService();
bool _control_1 = false;
bool get control_1 => _control_1;
bool _control_2 = false;
bool get control_2 => _control_2;
ControlProvider() {
connectMqtt();
getRelayStatus();
}
ResultState mqttState = ResultState.initial;
ResultState subscribeState = ResultState.initial;
// ResultState mqttState = ResultState.initial;
// ResultState subscribeState = ResultState.initial;
Future<void> connectMqtt() async {
mqttState = ResultState.loading;
subscribeState = ResultState.loading;
notifyListeners();
ResultState relayState = ResultState.initial;
try {
final result = await _mqttService.setupMqtt();
if (result == ResultState.hasData) {
mqttState = result;
final result2 = await _mqttService.subscribeToRelayStatus();
// if (result2 == true) {
// subscribeState = ResultState.hasData;
// _control_1 = true;
// Future<void> connectMqtt() async {
// mqttState = ResultState.loading;
// subscribeState = ResultState.loading;
// notifyListeners();
// try {
// final result = await _mqttService.setupMqtt();
// if (result == ResultState.hasData) {
// mqttState = result;
// final result2 = await _mqttService.subscribeToRelayStatus();
// // if (result2 == true) {
// // subscribeState = ResultState.hasData;
// // _control_1 = true;
// // } else {
// // subscribeState = ResultState.hasData;
// // _control_1 = false;
// // }
// } else {
// subscribeState = ResultState.hasData;
// _control_1 = false;
// mqttState = ResultState.error;
// }
// } catch (e) {
// mqttState = ResultState.error;
// print(e);
// }
// notifyListeners();
// }
Future<void> getRelayStatus() async {
relayState = ResultState.loading;
notifyListeners();
try {
final result = await _appService.getRelayStatus();
if (result.success == true) {
for (var element in result.data!) {
if (element.number == 1) {
switchControl1(element.currentStatus ?? false);
}
if (element.number == 2) {
switchControl2(element.currentStatus ?? false);
}
}
relayState = ResultState.hasData;
notifyListeners();
} else {
mqttState = ResultState.error;
}
} catch (e) {
mqttState = ResultState.error;
print(e);
}
relayState = ResultState.error;
notifyListeners();
}
Future<void> disconnectMqtt() async {
try {
await _mqttService.disconnectMqtt();
} catch (e) {
print(e);
rethrow;
}
relayState = ResultState.error;
notifyListeners();
}
@override
void dispose() {
disconnectMqtt();
super.dispose();
}
void switchControl1() {
_control_1 = !_control_1;
notifyListeners();
}
Future<ResultState> publishMessage(String topic, String message) async {
try {
final result = await _mqttService.publishMessage(topic, message);
return result;
} catch (e) {
print(e);
rethrow;
}
}
Future<void> subscribeToTopic(String topic) async {
try {
await _mqttService.subscribeToTopic(topic);
} catch (e) {
print(e);
rethrow;
// Future<void> disconnectMqtt() async {
// try {
// await _mqttService.disconnectMqtt();
// } catch (e) {
// print(e);
// rethrow;
// }
// notifyListeners();
// }
// @override
// void dispose() {
// disconnectMqtt();
// super.dispose();
// }
void switchControl1(bool value) {
_control_1 = value;
notifyListeners();
}
void switchControl2(bool value) {
_control_2 = value;
notifyListeners();
}
// Future<ResultState> publishMessage(String topic, String message) async {
// try {
// final result = await _mqttService.publishMessage(topic, message);
// return result;
// } catch (e) {
// print(e);
// rethrow;
// }
// }
// Future<void> subscribeToTopic(String topic) async {
// try {
// await _mqttService.subscribeToTopic(topic);
// } catch (e) {
// print(e);
// rethrow;
// }
// }
}

View File

@ -1,6 +1,8 @@
import 'package:agrilink_vocpro/core/constant/app_color.dart';
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:agrilink_vocpro/core/state/result_state.dart';
import 'package:agrilink_vocpro/features/control/provider/control_provider.dart';
import 'package:bootstrap_icons/bootstrap_icons.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
@ -11,6 +13,7 @@ class ControlScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final provider = Provider.of<ControlProvider>(context, listen: true);
return Scaffold(
appBar: AppBar(
title: Text('Control', style: AppTheme.labelMedium),
@ -18,40 +21,115 @@ class ControlScreen extends StatelessWidget {
backgroundColor: Colors.white,
scrolledUnderElevation: 0,
),
body: Consumer<ControlProvider>(
builder: (context, provider, child) {
return SafeArea(
body: RefreshIndicator(
onRefresh: () async =>
await context.read<ControlProvider>().getRelayStatus(),
child: SafeArea(
child: ListView(
children: [
Center(
child: provider.mqttState == ResultState.loading
? const CupertinoActivityIndicator()
: provider.mqttState == ResultState.hasData
? const Text('Terhubung ke Broker')
: const Text('Gagal terhubung ke Broker'),
),
SizedBox(height: 16.h),
ListTile(
title: Text('Control 1', style: AppTheme.labelMedium),
subtitle: const Text('Control 1 description'),
trailing: Switch(
value: provider.control_1,
onChanged: (value) {
provider.control_1 == false
? provider.publishMessage(
'smartfarming/relay/232', 'ON')
: provider.publishMessage(
'smartfarming/relay/232', 'OFF');
provider.switchControl1();
GridView(
padding: EdgeInsets.all(16.r),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16.r,
mainAxisSpacing: 16.r,
childAspectRatio: 1.4.h,
),
children: [
ControlButtonWidget(
title: 'Katup Air',
subtitle: 'Relay 1',
isActive: provider.control_1,
onTap: () {},
),
ControlButtonWidget(
title: 'Lampu Utama',
subtitle: 'Relay 2',
isActive: provider.control_2,
onTap: () {},
),
]),
],
),
),
),
);
}
}
class ControlButtonWidget extends StatelessWidget {
const ControlButtonWidget({
super.key,
required this.title,
required this.subtitle,
required this.isActive,
required this.onTap,
});
final String title;
final String subtitle;
final bool isActive;
final Function() onTap;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(16.r),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.r),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 1.r,
blurRadius: 16.r,
offset: Offset(0, 12.r),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: AppTheme.labelMedium),
Text(subtitle, style: AppTheme.labelSmall),
const Spacer(),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Consumer<ControlProvider>(
builder: (context, provider, child) {
switch (provider.relayState) {
case ResultState.loading:
return CircleAvatar(
radius: 20.r,
backgroundColor: Colors.transparent,
child: const CupertinoActivityIndicator(),
);
default:
return InkWell(
highlightColor: Colors.black,
onTap: onTap,
child: CircleAvatar(
radius: 20.r,
backgroundColor: isActive
? AppColor.secondary
: Colors.grey.shade400,
child: const Icon(
BootstrapIcons.power,
color: Colors.white,
),
),
);
}
},
),
),
// Control lainnya...
],
)
],
),
);
},
),
);
}
}

View File

@ -23,7 +23,7 @@ class ConductivityScreen extends StatelessWidget {
padding: EdgeInsets.only(right: 16),
child: Icon(
Icons.electric_bolt_rounded,
color: Colors.blue,
color: Colors.teal,
),
)
],
@ -38,7 +38,7 @@ class ConductivityScreen extends StatelessWidget {
Icon(
Icons.electric_bolt_rounded,
size: 64.r,
color: Colors.blue,
color: Colors.teal,
),
Text('$value µS/cm', style: AppTheme.headline1),
],
@ -70,7 +70,12 @@ class ConductivityScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(16.w),
border: Border.all(color: Colors.grey.shade300, width: 1.w),
),
child: const GarphicWidget(),
child: const GarphicWidget(
gradientColors: [
Colors.cyan,
Colors.teal,
],
),
),
)
],

View File

@ -114,9 +114,15 @@ class HumidityScreen extends StatelessWidget {
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
border: Border.all(
color: Colors.grey.shade300, width: 1.w)),
child: const GarphicWidget()),
border:
Border.all(color: Colors.grey.shade300, width: 1.w)),
child: GarphicWidget(
gradientColors: [
Colors.blue.shade200,
Colors.blue,
],
),
),
),
SizedBox(height: 16.h),
Padding(

View File

@ -104,13 +104,18 @@ class LightScreen extends StatelessWidget {
const Text('Grafik'),
SizedBox(height: 16.h),
AspectRatio(
aspectRatio: 1.5.h,
aspectRatio: 1.8.h,
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300, width: 1.w),
borderRadius: BorderRadius.circular(16.w),
),
child: const GarphicWidget(),
child: GarphicWidget(
gradientColors: [
Colors.yellow.shade100,
Colors.orange.shade200,
],
),
),
)
// Row(

View File

@ -41,7 +41,7 @@ class NitrogenScreen extends StatelessWidget {
size: 64.r,
color: Colors.blue,
),
Text('$value µS/cm', style: AppTheme.headline1),
Text('$value ppm', style: AppTheme.headline1),
],
),
SizedBox(height: 32.h),
@ -71,7 +71,12 @@ class NitrogenScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(16.w),
border: Border.all(color: Colors.grey.shade300, width: 1.w),
),
child: const GarphicWidget(),
child: GarphicWidget(
gradientColors: [
Colors.blue.shade200,
Colors.blue,
],
),
),
)
],

View File

@ -167,7 +167,12 @@ class PhScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(16.w),
border: Border.all(color: Colors.grey.shade300, width: 1.w),
),
child: const GarphicWidget(),
child: GarphicWidget(
gradientColors: [
Colors.amber.shade200,
Colors.orange,
],
),
),
)
],

View File

@ -71,7 +71,12 @@ class PhosphorusScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(16.w),
border: Border.all(color: Colors.grey.shade300, width: 1.w),
),
child: const GarphicWidget(),
child: GarphicWidget(
gradientColors: [
Colors.blue.shade200,
Colors.blue,
],
),
),
)
],

View File

@ -71,7 +71,12 @@ class PotassiumScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(16.w),
border: Border.all(color: Colors.grey.shade300, width: 1.w),
),
child: const GarphicWidget(),
child: const GarphicWidget(
gradientColors: [
Colors.teal,
Colors.green,
],
),
),
)
],

View File

@ -1,4 +1,7 @@
import 'package:agrilink_vocpro/core/constant/app_constant.dart';
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:agrilink_vocpro/core/widgets/show_info.dart';
import 'package:agrilink_vocpro/features/home/widgets/graphic_widget.dart';
import 'package:bootstrap_icons/bootstrap_icons.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -34,10 +37,8 @@ class SoilMoistureScreen extends StatelessWidget {
),
body: SafeArea(
child: ListView(
padding: EdgeInsets.all(16.w),
children: [
SizedBox(
height: MediaQuery.of(context).size.height * 0.05,
),
SizedBox(
height: 280.h,
child: Stack(
@ -80,7 +81,47 @@ class SoilMoistureScreen extends StatelessWidget {
],
),
),
const SizedBox(height: 16),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Soil Temperature',
style: AppTheme.labelMedium,
textAlign: TextAlign.center,
),
IconButton(
iconSize: 20.r,
color: Colors.blue,
onPressed: () {
showInfo(
context,
'Soil Temperature',
AppConstant.soilTempInfo,
);
},
icon: const Icon(BootstrapIcons.info_circle))
],
),
SizedBox(height: 16.h),
const Text('Grafik'),
SizedBox(height: 16.h),
AspectRatio(
aspectRatio: 1.8.h,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16.w),
border: Border.all(color: Colors.grey.shade300, width: 1.w),
),
child: GarphicWidget(
gradientColors: [
Colors.blue.shade200,
Colors.blue,
],
),
),
)
],
),
),

View File

@ -1,5 +1,6 @@
import 'package:agrilink_vocpro/core/constant/app_constant.dart';
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:agrilink_vocpro/core/widgets/show_info.dart';
import 'package:agrilink_vocpro/features/home/widgets/graphic_widget.dart';
import 'package:bootstrap_icons/bootstrap_icons.dart';
import 'package:flutter/material.dart';
@ -85,8 +86,7 @@ class SoilTemperatureScreen extends StatelessWidget {
],
),
),
const SizedBox(height: 16),
const SizedBox(height: 16),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -218,7 +218,12 @@ class SoilTemperatureScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(16.w),
border: Border.all(color: Colors.grey.shade300, width: 1.w),
),
child: const GarphicWidget(),
child: const GarphicWidget(
gradientColors: [
Colors.cyan,
Colors.amber,
],
),
),
)
],
@ -226,31 +231,4 @@ class SoilTemperatureScreen extends StatelessWidget {
),
);
}
Future<dynamic> showInfo(BuildContext context, String title, String content) {
return showDialog(
context: context,
builder: (context) => AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(title),
const SizedBox(height: 16),
Text(
style: Theme.of(context).textTheme.bodySmall,
content,
),
],
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('OK'),
)
],
),
);
}
}

View File

@ -75,7 +75,7 @@ class TemperatureScreen extends StatelessWidget {
),
progressBar: const GaugeBasicProgressBar(
gradient: GaugeAxisGradient(colors: [
Colors.blue,
Colors.white12,
Colors.orange,
]),
),
@ -211,7 +211,12 @@ class TemperatureScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(16.w),
border: Border.all(color: Colors.grey.shade300, width: 1.w),
),
child: const GarphicWidget(),
child: const GarphicWidget(
gradientColors: [
Colors.cyan,
Colors.amber,
],
),
),
)
],

View File

@ -1,191 +1,115 @@
import 'package:agrilink_vocpro/core/constant/app_color.dart';
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class GarphicWidget extends StatelessWidget {
const GarphicWidget({super.key, thi});
const GarphicWidget({super.key, required this.gradientColors});
final List<Color> gradientColors;
@override
Widget build(BuildContext context) {
return BarChart(
BarChartData(
barTouchData: barTouchData,
titlesData: titlesData,
borderData: borderData,
barGroups: barGroups,
gridData: const FlGridData(show: false),
alignment: BarChartAlignment.spaceAround,
maxY: 20,
return Padding(
padding: EdgeInsets.all(8.r),
child: LineChart(
mainData(),
),
);
}
}
BarTouchData get barTouchData => BarTouchData(
enabled: false,
touchTooltipData: BarTouchTooltipData(
getTooltipColor: (group) => Colors.transparent,
tooltipPadding: EdgeInsets.zero,
tooltipMargin: 8,
getTooltipItem: (
BarChartGroupData group,
int groupIndex,
BarChartRodData rod,
int rodIndex,
) {
return BarTooltipItem(
rod.toY.round().toString(),
const TextStyle(
color: AppColor.textDark,
fontWeight: FontWeight.bold,
),
);
},
),
);
Widget getTitles(double value, TitleMeta meta) {
const style = TextStyle(
color: AppColor.textDark,
fontWeight: FontWeight.bold,
fontSize: 14,
);
String text;
Widget bottomTitleWidgets(double value, TitleMeta meta) {
TextStyle style = AppTheme.labelSmall;
Widget text;
switch (value.toInt()) {
case 0:
text = 'Mon';
break;
case 1:
text = 'Tue';
break;
case 2:
text = 'Wed';
break;
case 3:
text = 'Thu';
break;
case 4:
text = 'Fri';
break;
case 5:
text = 'Sat';
text = Text('01.00', style: style);
break;
case 6:
text = 'Sun';
text = Text('06.00', style: style);
break;
case 12:
text = Text('12.00', style: style);
break;
case 18:
text = Text('18.00', style: style);
break;
case 23:
text = Text('23.00', style: style);
break;
default:
text = '';
text = Text('', style: style);
break;
}
return SideTitleWidget(
axisSide: meta.axisSide,
space: 4,
child: Text(text, style: style),
child: text,
);
}
FlTitlesData get titlesData => const FlTitlesData(
LineChartData mainData() {
return LineChartData(
gridData: const FlGridData(
show: false,
),
titlesData: FlTitlesData(
show: true,
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 30,
getTitlesWidget: getTitles,
interval: 1,
getTitlesWidget: bottomTitleWidgets,
),
),
leftTitles: AxisTitles(
leftTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
rightTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
);
FlBorderData get borderData => FlBorderData(
borderData: FlBorderData(
show: false,
border: Border.all(color: const Color(0xff37434d)),
),
minX: 0,
maxX: 24,
minY: 0,
maxY: 100,
lineBarsData: [
LineChartBarData(
spots: const [
FlSpot(0, 38),
FlSpot(1, 42),
FlSpot(2, 50),
FlSpot(3, 53),
FlSpot(4, 58),
FlSpot(5, 64),
FlSpot(7, 49),
],
isCurved: true,
gradient: LinearGradient(
colors: gradientColors,
),
barWidth: 5,
isStrokeCapRound: true,
dotData: const FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
gradient: LinearGradient(
colors: gradientColors
.map((color) => color.withOpacity(0.3))
.toList()),
),
),
],
);
LinearGradient get _barsGradient => const LinearGradient(
colors: [
AppColor.secondary,
AppColor.ternary,
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
);
List<BarChartGroupData> get barGroups => [
BarChartGroupData(
x: 0,
barRods: [
BarChartRodData(
toY: 8,
gradient: _barsGradient,
)
],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 1,
barRods: [
BarChartRodData(
toY: 10,
gradient: _barsGradient,
)
],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 2,
barRods: [
BarChartRodData(
toY: 14,
gradient: _barsGradient,
)
],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 3,
barRods: [
BarChartRodData(
toY: 15,
gradient: _barsGradient,
)
],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 4,
barRods: [
BarChartRodData(
toY: 13,
gradient: _barsGradient,
)
],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 5,
barRods: [
BarChartRodData(
toY: 10,
gradient: _barsGradient,
)
],
showingTooltipIndicators: [0],
),
BarChartGroupData(
x: 6,
barRods: [
BarChartRodData(
toY: 16,
gradient: _barsGradient,
)
],
showingTooltipIndicators: [0],
),
];
}
}

View File

@ -64,12 +64,12 @@ class ListDataFromCensorDht extends StatelessWidget {
DataDisplayerWidget(
title: 'Temperature',
subtitle: 'suhu greenhouse',
value: '28',
value: '43',
unit: '°C',
icon: BootstrapIcons.thermometer_half,
color: Colors.white,
onTap: () async {
await context.push('${AppRoute.temperature}/28');
await context.push('${AppRoute.temperature}/43');
},
),
DataDisplayerWidget(