From 04769c4f006ae378515eb98e413be0ffbae1f6c6 Mon Sep 17 00:00:00 2001 From: Syaroful Date: Wed, 9 Oct 2024 08:21:10 +0700 Subject: [PATCH] fix: fixing the grafik UI for sensor data --- agrilink_vocpro/assets/images/valve.png | Bin 0 -> 44937 bytes .../lib/core/constant/app_constant.dart | 2 +- .../lib/core/widgets/show_info.dart | 28 ++ .../lib/data/model/relay_response.dart | 66 +++++ .../lib/domain/service/app_service.dart | 16 +- .../control/provider/control_provider.dart | 163 +++++++---- .../features/control/view/control_screen.dart | 142 +++++++--- .../view/conductivity_screen.dart | 11 +- .../pages/humidity/view/humidity_screen.dart | 20 +- .../home/pages/light/view/light_screen.dart | 9 +- .../pages/nitrogen/view/nitrogen_screen.dart | 9 +- .../home/pages/ph/view/ph_screen.dart | 7 +- .../phosphorus/view/phosphorus_screen.dart | 7 +- .../potassium/view/potassium_screen.dart | 7 +- .../view/soil_moisture_screen.dart | 49 +++- .../view/soil_temperature_screen.dart | 38 +-- .../temperature/view/temperature_screen.dart | 9 +- .../features/home/widgets/graphic_widget.dart | 268 +++++++----------- .../widgets/list_data_from_censor_dht.dart | 4 +- 19 files changed, 530 insertions(+), 325 deletions(-) create mode 100644 agrilink_vocpro/assets/images/valve.png create mode 100644 agrilink_vocpro/lib/core/widgets/show_info.dart create mode 100644 agrilink_vocpro/lib/data/model/relay_response.dart diff --git a/agrilink_vocpro/assets/images/valve.png b/agrilink_vocpro/assets/images/valve.png new file mode 100644 index 0000000000000000000000000000000000000000..5a4bbfd689458d91edf30d9760332610449c5e2c GIT binary patch literal 44937 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%0AaEQqlnVpY&eJ8)Y(z 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 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'), + ) + ], + ), + ); +} diff --git a/agrilink_vocpro/lib/data/model/relay_response.dart b/agrilink_vocpro/lib/data/model/relay_response.dart new file mode 100644 index 0000000..bdae310 --- /dev/null +++ b/agrilink_vocpro/lib/data/model/relay_response.dart @@ -0,0 +1,66 @@ +class RelayResponse { + bool? success; + List? data; + + RelayResponse({this.success, this.data}); + + RelayResponse.fromJson(Map json) { + success = json['success']; + if (json['data'] != null) { + data = []; + json['data'].forEach((v) { + data!.add(Relay.fromJson(v)); + }); + } + } + + Map toJson() { + final Map data = {}; + 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 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 toJson() { + final Map data = {}; + 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; + } +} diff --git a/agrilink_vocpro/lib/domain/service/app_service.dart b/agrilink_vocpro/lib/domain/service/app_service.dart index bb89afc..0d9cb8a 100644 --- a/agrilink_vocpro/lib/domain/service/app_service.dart +++ b/agrilink_vocpro/lib/domain/service/app_service.dart @@ -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 getGreenHouseData() async { - try {} on DioException catch (e) { + Future 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); } diff --git a/agrilink_vocpro/lib/features/control/provider/control_provider.dart b/agrilink_vocpro/lib/features/control/provider/control_provider.dart index 42b96a6..21ed0dd 100644 --- a/agrilink_vocpro/lib/features/control/provider/control_provider.dart +++ b/agrilink_vocpro/lib/features/control/provider/control_provider.dart @@ -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 connectMqtt() async { - mqttState = ResultState.loading; - subscribeState = ResultState.loading; + ResultState relayState = ResultState.initial; + + // Future 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 { + // mqttState = ResultState.error; + // } + // } catch (e) { + // mqttState = ResultState.error; + // print(e); + // } + + // notifyListeners(); + // } + + Future getRelayStatus() async { + relayState = 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; - // } + 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; + relayState = ResultState.error; + notifyListeners(); } } catch (e) { - mqttState = ResultState.error; - print(e); - } - - notifyListeners(); - } - - Future disconnectMqtt() async { - try { - await _mqttService.disconnectMqtt(); - } catch (e) { - print(e); - rethrow; - } - notifyListeners(); - } - - @override - void dispose() { - disconnectMqtt(); - super.dispose(); - } - - void switchControl1() { - _control_1 = !_control_1; - notifyListeners(); - } - - Future publishMessage(String topic, String message) async { - try { - final result = await _mqttService.publishMessage(topic, message); - return result; - } catch (e) { + relayState = ResultState.error; + notifyListeners(); print(e); rethrow; } } - Future subscribeToTopic(String topic) async { - try { - await _mqttService.subscribeToTopic(topic); - } catch (e) { - print(e); - rethrow; - } + // Future 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 publishMessage(String topic, String message) async { + // try { + // final result = await _mqttService.publishMessage(topic, message); + // return result; + // } catch (e) { + // print(e); + // rethrow; + // } + // } + + // Future subscribeToTopic(String topic) async { + // try { + // await _mqttService.subscribeToTopic(topic); + // } catch (e) { + // print(e); + // rethrow; + // } + // } } diff --git a/agrilink_vocpro/lib/features/control/view/control_screen.dart b/agrilink_vocpro/lib/features/control/view/control_screen.dart index c824b06..87e63ec 100644 --- a/agrilink_vocpro/lib/features/control/view/control_screen.dart +++ b/agrilink_vocpro/lib/features/control/view/control_screen.dart @@ -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(context, listen: true); return Scaffold( appBar: AppBar( title: Text('Control', style: AppTheme.labelMedium), @@ -18,39 +21,114 @@ class ControlScreen extends StatelessWidget { backgroundColor: Colors.white, scrolledUnderElevation: 0, ), - body: Consumer( - builder: (context, provider, child) { - return 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(); - }, + body: RefreshIndicator( + onRefresh: () async => + await context.read().getRelayStatus(), + child: SafeArea( + child: ListView( + children: [ + SizedBox(height: 16.h), + 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, ), - ), - // Control lainnya... - ], - ), - ); - }, + 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( + 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, + ), + ), + ); + } + }, + ), + ], + ) + ], ), ); } diff --git a/agrilink_vocpro/lib/features/home/pages/conductivity/view/conductivity_screen.dart b/agrilink_vocpro/lib/features/home/pages/conductivity/view/conductivity_screen.dart index 2129116..3eb7ae7 100644 --- a/agrilink_vocpro/lib/features/home/pages/conductivity/view/conductivity_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/conductivity/view/conductivity_screen.dart @@ -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, + ], + ), ), ) ], diff --git a/agrilink_vocpro/lib/features/home/pages/humidity/view/humidity_screen.dart b/agrilink_vocpro/lib/features/home/pages/humidity/view/humidity_screen.dart index 40142d3..b3d9cb6 100644 --- a/agrilink_vocpro/lib/features/home/pages/humidity/view/humidity_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/humidity/view/humidity_screen.dart @@ -110,13 +110,19 @@ class HumidityScreen extends StatelessWidget { AspectRatio( aspectRatio: 2.h, child: Container( - margin: EdgeInsets.symmetric(horizontal: 16.w), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16.w), - border: Border.all( - color: Colors.grey.shade300, width: 1.w)), - child: const GarphicWidget()), + margin: EdgeInsets.symmetric(horizontal: 16.w), + 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, + ], + ), + ), ), SizedBox(height: 16.h), Padding( diff --git a/agrilink_vocpro/lib/features/home/pages/light/view/light_screen.dart b/agrilink_vocpro/lib/features/home/pages/light/view/light_screen.dart index 683a237..2a80b81 100644 --- a/agrilink_vocpro/lib/features/home/pages/light/view/light_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/light/view/light_screen.dart @@ -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( diff --git a/agrilink_vocpro/lib/features/home/pages/nitrogen/view/nitrogen_screen.dart b/agrilink_vocpro/lib/features/home/pages/nitrogen/view/nitrogen_screen.dart index 5753173..9b99e91 100644 --- a/agrilink_vocpro/lib/features/home/pages/nitrogen/view/nitrogen_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/nitrogen/view/nitrogen_screen.dart @@ -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, + ], + ), ), ) ], diff --git a/agrilink_vocpro/lib/features/home/pages/ph/view/ph_screen.dart b/agrilink_vocpro/lib/features/home/pages/ph/view/ph_screen.dart index 85ea0d7..a8c7517 100644 --- a/agrilink_vocpro/lib/features/home/pages/ph/view/ph_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/ph/view/ph_screen.dart @@ -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, + ], + ), ), ) ], diff --git a/agrilink_vocpro/lib/features/home/pages/phosphorus/view/phosphorus_screen.dart b/agrilink_vocpro/lib/features/home/pages/phosphorus/view/phosphorus_screen.dart index d273827..e77cc61 100644 --- a/agrilink_vocpro/lib/features/home/pages/phosphorus/view/phosphorus_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/phosphorus/view/phosphorus_screen.dart @@ -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, + ], + ), ), ) ], diff --git a/agrilink_vocpro/lib/features/home/pages/potassium/view/potassium_screen.dart b/agrilink_vocpro/lib/features/home/pages/potassium/view/potassium_screen.dart index d38d726..6be5a5a 100644 --- a/agrilink_vocpro/lib/features/home/pages/potassium/view/potassium_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/potassium/view/potassium_screen.dart @@ -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, + ], + ), ), ) ], diff --git a/agrilink_vocpro/lib/features/home/pages/soil_moisture/view/soil_moisture_screen.dart b/agrilink_vocpro/lib/features/home/pages/soil_moisture/view/soil_moisture_screen.dart index 05de5ca..c05a466 100644 --- a/agrilink_vocpro/lib/features/home/pages/soil_moisture/view/soil_moisture_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/soil_moisture/view/soil_moisture_screen.dart @@ -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, + ], + ), + ), + ) ], ), ), diff --git a/agrilink_vocpro/lib/features/home/pages/soil_temperature/view/soil_temperature_screen.dart b/agrilink_vocpro/lib/features/home/pages/soil_temperature/view/soil_temperature_screen.dart index 5dae429..6715b63 100644 --- a/agrilink_vocpro/lib/features/home/pages/soil_temperature/view/soil_temperature_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/soil_temperature/view/soil_temperature_screen.dart @@ -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 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'), - ) - ], - ), - ); - } } diff --git a/agrilink_vocpro/lib/features/home/pages/temperature/view/temperature_screen.dart b/agrilink_vocpro/lib/features/home/pages/temperature/view/temperature_screen.dart index 3340242..dad687f 100644 --- a/agrilink_vocpro/lib/features/home/pages/temperature/view/temperature_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/temperature/view/temperature_screen.dart @@ -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, + ], + ), ), ) ], diff --git a/agrilink_vocpro/lib/features/home/widgets/graphic_widget.dart b/agrilink_vocpro/lib/features/home/widgets/graphic_widget.dart index 40630d2..2660ba8 100644 --- a/agrilink_vocpro/lib/features/home/widgets/graphic_widget.dart +++ b/agrilink_vocpro/lib/features/home/widgets/graphic_widget.dart @@ -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 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 bottomTitleWidgets(double value, TitleMeta meta) { + TextStyle style = AppTheme.labelSmall; + Widget text; + switch (value.toInt()) { + case 1: + text = Text('01.00', style: style); + break; + case 6: + 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('', style: style); + break; + } + + return SideTitleWidget( + axisSide: meta.axisSide, + child: text, ); - -Widget getTitles(double value, TitleMeta meta) { - const style = TextStyle( - color: AppColor.textDark, - fontWeight: FontWeight.bold, - fontSize: 14, - ); - String 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'; - break; - case 6: - text = 'Sun'; - break; - default: - text = ''; - break; } - return SideTitleWidget( - axisSide: meta.axisSide, - space: 4, - child: Text(text, style: style), - ); -} -FlTitlesData get titlesData => const FlTitlesData( - show: true, - bottomTitles: AxisTitles( - sideTitles: SideTitles( - showTitles: true, - reservedSize: 30, - getTitlesWidget: getTitles, + 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, + interval: 1, + getTitlesWidget: bottomTitleWidgets, + ), + ), + leftTitles: const AxisTitles( + sideTitles: SideTitles(showTitles: false), ), ), - leftTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), + borderData: FlBorderData( + show: false, + border: Border.all(color: const Color(0xff37434d)), ), - topTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - rightTitles: AxisTitles( - sideTitles: SideTitles(showTitles: false), - ), - ); - -FlBorderData get borderData => FlBorderData( - show: false, - ); - -LinearGradient get _barsGradient => const LinearGradient( - colors: [ - AppColor.secondary, - AppColor.ternary, + 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()), + ), + ), ], - begin: Alignment.bottomCenter, - end: Alignment.topCenter, ); - -List 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], - ), - ]; + } +} diff --git a/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_dht.dart b/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_dht.dart index 015f729..628ca9d 100644 --- a/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_dht.dart +++ b/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_dht.dart @@ -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(