diff --git a/agrilink_vocpro/assets/images/error_image.png b/agrilink_vocpro/assets/images/error_image.png new file mode 100644 index 0000000..48a9090 Binary files /dev/null and b/agrilink_vocpro/assets/images/error_image.png differ diff --git a/agrilink_vocpro/assets/images/no_data_image.png b/agrilink_vocpro/assets/images/no_data_image.png new file mode 100644 index 0000000..2ef663a Binary files /dev/null and b/agrilink_vocpro/assets/images/no_data_image.png differ diff --git a/agrilink_vocpro/lib/core/constant/app_constant.dart b/agrilink_vocpro/lib/core/constant/app_constant.dart new file mode 100644 index 0000000..a7dcbf6 --- /dev/null +++ b/agrilink_vocpro/lib/core/constant/app_constant.dart @@ -0,0 +1,13 @@ +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 mqttServer = 'armadillo.rmq.cloudamqp.com'; + static const String mqttUsername = 'obyskxhx:obyskxhx'; + static const String mqttPassword = 'Fe_3_tBuwmc8vMMqT2hYiboTsBlBmPz1'; + + 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.'; +} diff --git a/agrilink_vocpro/lib/core/constant/app_contant.dart b/agrilink_vocpro/lib/core/constant/app_contant.dart deleted file mode 100644 index 74b3f0c..0000000 --- a/agrilink_vocpro/lib/core/constant/app_contant.dart +++ /dev/null @@ -1,6 +0,0 @@ -class AppContant { - static const String appName = 'Kebun Pintar'; - static const String appVersion = '1.0.0'; - - static const String baseUrl = 'https://kebunpintar.id/api/v1'; -} diff --git a/agrilink_vocpro/lib/core/route/app_route.dart b/agrilink_vocpro/lib/core/route/app_route.dart index 9b7b193..eebfe73 100644 --- a/agrilink_vocpro/lib/core/route/app_route.dart +++ b/agrilink_vocpro/lib/core/route/app_route.dart @@ -1,8 +1,15 @@ import 'package:agrilink_vocpro/features/auth/view/login_screen.dart'; import 'package:agrilink_vocpro/features/dashboard/view/dashboard_screen.dart'; +import 'package:agrilink_vocpro/features/home/pages/conductivity/view/conductivity_screen.dart'; import 'package:agrilink_vocpro/features/home/pages/humidity/view/humidity_screen.dart'; import 'package:agrilink_vocpro/features/home/pages/light/view/light_screen.dart'; +import 'package:agrilink_vocpro/features/home/pages/nitrogen/view/nitrogen_screen.dart'; import 'package:agrilink_vocpro/features/home/pages/ph/view/ph_screen.dart'; +import 'package:agrilink_vocpro/features/home/pages/phosphorus/view/phosphorus_screen.dart'; +import 'package:agrilink_vocpro/features/home/pages/potassium/view/potassium_screen.dart'; +import 'package:agrilink_vocpro/features/home/pages/soil_moisture/view/soil_moisture_screen.dart'; +import 'package:agrilink_vocpro/features/home/pages/soil_temperature/view/soil_temperature_screen.dart'; +import 'package:agrilink_vocpro/features/home/pages/temperature/view/temperature_screen.dart'; import 'package:agrilink_vocpro/features/splash/view/splash_screen.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -15,12 +22,15 @@ class AppRoute { static const String profile = '/profile'; static const String setting = '/setting'; static const String humidity = '/dashboard/humidity'; - static const String temperature = '/temperature'; - static const String soil = '/soil'; + static const String temperature = '/dashboard/temperature'; + static const String soilTemperature = '/dashboard/soil_temperature'; + static const String soilMoisture = '/dashboard/soil_moisture'; static const String light = '/dashboard/light'; static const String ph = '/dashboard/ph'; - static const String water = '/water'; - static const String acidity = '/acidity'; + static const String conductivity = '/dashboard/conductivity'; + static const String nitrogen = '/dashboard/nitrogen'; + static const String phosphorus = '/dashboard/phosphorus'; + static const String potassium = '/dashboard/potassium'; static final GoRouter router = GoRouter( initialLocation: root, @@ -35,35 +45,30 @@ class AppRoute { path: login, builder: (context, state) => const LoginScreen(), ), - //dashboard - GoRoute( - path: dashboard, - builder: (context, state) => const DashboardScreen(), - ), GoRoute( path: dashboard, builder: (context, state) => const DashboardScreen(), routes: [ - GoRoute( - path: 'humidity', - builder: (context, state) => const HumidityScreen(), - ), - GoRoute( - path: 'light/:value', - builder: (context, state) { - final double value = - double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; - return LightScreen(lightIntensity: value); - }, - ), - GoRoute( - path: 'ph/:value', - builder: (context, state) { - final double value = - double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; - return PhScreen(phValue: value); - }, - ), + // humidity + buildHumidityRoute(), + // light intensity + buildLightIntensityRoute(), + // temperature + buildTemperatureRoute(), + // ph + buildAcidityRoute(), + // soil moisture + buildSoilTempRoute(), + // soil moisture + buildSoilMoistureRoute(), + // conductivity + buildConductivityRoute(), + // nitrogen + buildNitrogenRoute(), + // phosphorus + buildPhosphorusRoute(), + // potassium + buildPotassiumRoute(), ], ), ], @@ -73,4 +78,114 @@ class AppRoute { ), ), ); + + static GoRoute buildPotassiumRoute() { + return GoRoute( + path: 'potassium/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return PotassiumScreen(potassium: value); + }, + ); + } + + static GoRoute buildPhosphorusRoute() { + return GoRoute( + path: 'phosphorus/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return PhosphorusScreen(phosphorus: value); + }, + ); + } + + static GoRoute buildNitrogenRoute() { + return GoRoute( + path: 'nitrogen/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return NitrogenScreen(nitrogen: value); + }, + ); + } + + static GoRoute buildConductivityRoute() { + return GoRoute( + path: 'conductivity/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return ConductivityScreen(conductivity: value); + }, + ); + } + + static GoRoute buildSoilMoistureRoute() { + return GoRoute( + path: 'soil_moisture/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return SoilMoistureScreen(moisture: value); + }, + ); + } + + static GoRoute buildSoilTempRoute() { + return GoRoute( + path: 'soil_temperature/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return SoilTemperatureScreen(temperature: value); + }, + ); + } + + static GoRoute buildAcidityRoute() { + return GoRoute( + path: 'ph/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return PhScreen(phValue: value); + }, + ); + } + + static GoRoute buildTemperatureRoute() { + return GoRoute( + path: 'temperature/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return TemperatureScreen(temperature: value); + }, + ); + } + + static GoRoute buildLightIntensityRoute() { + return GoRoute( + path: 'light/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return LightScreen(lightIntensity: value); + }, + ); + } + + static GoRoute buildHumidityRoute() { + return GoRoute( + path: 'humidity/:value', + builder: (context, state) { + final double value = + double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; + return HumidityScreen(humidity: value); + }, + ); + } } diff --git a/agrilink_vocpro/lib/domain/provider/censor_provider.dart b/agrilink_vocpro/lib/domain/provider/censor_provider.dart deleted file mode 100644 index 194d624..0000000 --- a/agrilink_vocpro/lib/domain/provider/censor_provider.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:flutter/material.dart'; - -class CensorProvider extends ChangeNotifier { - Future setupMqtt() async {} -} diff --git a/agrilink_vocpro/lib/domain/service/app_service.dart b/agrilink_vocpro/lib/domain/service/app_service.dart new file mode 100644 index 0000000..bb89afc --- /dev/null +++ b/agrilink_vocpro/lib/domain/service/app_service.dart @@ -0,0 +1,20 @@ +import 'package:agrilink_vocpro/core/constant/app_contant.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; + +class AppService { + final Dio _dioWithoutInterceptor = Dio( + BaseOptions( + baseUrl: AppConstant.baseUrl, + ), + ); + + Future getGreenHouseData() async { + try {} on DioException catch (e) { + if (kDebugMode) { + print(e); + } + rethrow; + } + } +} diff --git a/agrilink_vocpro/lib/domain/service/mqtt_service.dart b/agrilink_vocpro/lib/domain/service/mqtt_service.dart index a7c4d31..21002a8 100644 --- a/agrilink_vocpro/lib/domain/service/mqtt_service.dart +++ b/agrilink_vocpro/lib/domain/service/mqtt_service.dart @@ -1,3 +1,6 @@ +import 'dart:convert'; + +import 'package:agrilink_vocpro/core/constant/app_constant.dart'; import 'package:agrilink_vocpro/core/state/result_state.dart'; import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart'; @@ -6,11 +9,11 @@ class MQTTService { MqttServerClient? client; Future setupMqtt() async { - client = MqttServerClient('armadillo.rmq.cloudamqp.com', ''); + client = MqttServerClient(AppConstant.mqttServer, ''); client!.port = 1883; client!.connectionMessage = MqttConnectMessage() - .authenticateAs('obyskxhx:obyskxhx', 'Fe_3_tBuwmc8vMMqT2hYiboTsBlBmPz1') + .authenticateAs(AppConstant.mqttUsername, AppConstant.mqttPassword) .withClientIdentifier('mobile_client_controller') .startClean() // reset session .withWillQos(MqttQos.atLeastOnce); @@ -90,14 +93,14 @@ class MQTTService { client!.updates!.listen( (List>? messages) { - print('MQTT: Message received!'); + print('MQTT: Subscribe Message received!'); if (messages != null && messages.isNotEmpty) { final MqttPublishMessage recMessage = messages[0].payload as MqttPublishMessage; final String payload = MqttPublishPayload.bytesToStringAsString( recMessage.payload.message); print( - 'MQTT: Message received on topic ${messages[0].topic}: $payload'); + 'MQTT: Subscribe Message received on topic ${messages[0].topic}: $payload'); if (payload == 'ON') { isActive = true; @@ -105,9 +108,11 @@ class MQTTService { } else if (payload == 'OFF') { isActive = false; // Update UI atau provider untuk menandakan relay OFF + } else { + print('MQTT: Invalid Subscribe message received'); } } else { - print('MQTT: No messages received'); + print('MQTT: No Subscribe messages received'); } }, ); @@ -122,4 +127,44 @@ class MQTTService { return false; } } + + Future subscribeToRelayStatus() async { + if (client != null && + client!.connectionStatus!.state == MqttConnectionState.connected) { + try { + print('MQTT: Subscribing to /smartfarming/getRelayStatus'); + client!.subscribe('smartfarming/getRelayStatus', MqttQos.atMostOnce); + print('MQTT: Subscribed to /smartfarming/getRelayStatus'); + + client!.updates! + .listen((List>? messages) { + if (messages != null && messages.isNotEmpty) { + final MqttPublishMessage recMessage = + messages[0].payload as MqttPublishMessage; + final String payload = MqttPublishPayload.bytesToStringAsString( + recMessage.payload.message); + print( + 'MQTT: Message received on topic ${messages[0].topic}: $payload'); + + // Parse the received JSON payload + final Map relayStatus = jsonDecode(payload); + + print('MQTT: Relay status: $relayStatus'); + + // Assuming you are using provider, notify it with new relay status + // _updateRelayStatus(relayStatus); + } else { + print('MQTT: No messages received'); + } + }); + return ResultState.hasData; + } catch (e) { + print('MQTT: Error subscribing: $e'); + return ResultState.error; + } + } else { + print('MQTT: Not connected, cannot subscribe.'); + return ResultState.error; + } + } } diff --git a/agrilink_vocpro/lib/domain/service/service.dart b/agrilink_vocpro/lib/domain/service/service.dart deleted file mode 100644 index 97df96f..0000000 --- a/agrilink_vocpro/lib/domain/service/service.dart +++ /dev/null @@ -1 +0,0 @@ -class Service {} diff --git a/agrilink_vocpro/lib/features/control/provider/control_provider.dart b/agrilink_vocpro/lib/features/control/provider/control_provider.dart index 6b56df4..42b96a6 100644 --- a/agrilink_vocpro/lib/features/control/provider/control_provider.dart +++ b/agrilink_vocpro/lib/features/control/provider/control_provider.dart @@ -25,14 +25,14 @@ class ControlProvider extends ChangeNotifier { final result = await _mqttService.setupMqtt(); if (result == ResultState.hasData) { mqttState = result; - final result2 = await _mqttService.subscribeToTopic('relay1'); - if (result2 == true) { - subscribeState = ResultState.hasData; - _control_1 = true; - } else { - subscribeState = ResultState.hasData; - _control_1 = false; - } + 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; } diff --git a/agrilink_vocpro/lib/features/control/view/control_screen.dart b/agrilink_vocpro/lib/features/control/view/control_screen.dart index 9595b7c..c824b06 100644 --- a/agrilink_vocpro/lib/features/control/view/control_screen.dart +++ b/agrilink_vocpro/lib/features/control/view/control_screen.dart @@ -18,55 +18,40 @@ class ControlScreen extends StatelessWidget { backgroundColor: Colors.white, scrolledUnderElevation: 0, ), - body: Consumer(builder: (context, provider, child) { - return SafeArea( + 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'), + 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(); + }, + ), + ), + // Control lainnya... + ], ), - 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('relay1', 'ON') - : provider.publishMessage('relay1', 'OFF'); - provider.switchControl1(); - // showDialog( - // context: context, - // builder: (context) => AlertDialog( - // title: const Text('Konfirmasi'), - // content: const Text('Atur Relay 1?'), - // actions: [ - // TextButton( - // onPressed: () { - // provider.control_1 == false - // ? provider.publishMessage('relay1', 'ON') - // : provider.publishMessage('relay1', 'OFF'); - // provider.switchControl1(); - // Navigator.pop(context); - // }, - // child: - // Text(provider.control_1 == false ? 'ON' : 'OFF'), - // ) - // ], - // ), - // ); - }, - ), - ), - // Control lainnya... - ], - )); - }), + ); + }, + ), ); } } 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 new file mode 100644 index 0000000..2129116 --- /dev/null +++ b/agrilink_vocpro/lib/features/home/pages/conductivity/view/conductivity_screen.dart @@ -0,0 +1,81 @@ +import 'package:agrilink_vocpro/core/constant/app_theme.dart'; +import 'package:agrilink_vocpro/features/home/widgets/graphic_widget.dart'; +import 'package:bootstrap_icons/bootstrap_icons.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class ConductivityScreen extends StatelessWidget { + const ConductivityScreen({super.key, this.conductivity = 0.0}); + + final double conductivity; + double get value => conductivity; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Conductivity', style: AppTheme.labelMedium), + centerTitle: true, + backgroundColor: Colors.white, + scrolledUnderElevation: 0, + actions: const [ + Padding( + padding: EdgeInsets.only(right: 16), + child: Icon( + Icons.electric_bolt_rounded, + color: Colors.blue, + ), + ) + ], + ), + body: Center( + child: ListView( + padding: EdgeInsets.all(16.w), + children: [ + SizedBox(height: 32.h), + Column( + children: [ + Icon( + Icons.electric_bolt_rounded, + size: 64.r, + color: Colors.blue, + ), + Text('$value µS/cm', style: AppTheme.headline1), + ], + ), + SizedBox(height: 32.h), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Daya Arus Listrik', + style: AppTheme.labelMedium, + textAlign: TextAlign.center, + ), + IconButton( + iconSize: 20.r, + color: Colors.blue, + onPressed: () {}, + icon: const Icon(BootstrapIcons.info_circle)) + ], + ), + SizedBox(height: 16.h), + const Text('Grafik'), + SizedBox(height: 16.h), + AspectRatio( + aspectRatio: 1.6.h, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16.w), + border: Border.all(color: Colors.grey.shade300, width: 1.w), + ), + child: const GarphicWidget(), + ), + ) + ], + ), + ), + ); + } +} 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 95ee1d3..40142d3 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 @@ -9,7 +9,10 @@ import 'package:gauge_indicator/gauge_indicator.dart'; import 'package:provider/provider.dart'; class HumidityScreen extends StatelessWidget { - const HumidityScreen({super.key}); + const HumidityScreen({super.key, this.humidity = 0}); + + final double humidity; + double get value => humidity; @override Widget build(BuildContext context) { 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 new file mode 100644 index 0000000..5753173 --- /dev/null +++ b/agrilink_vocpro/lib/features/home/pages/nitrogen/view/nitrogen_screen.dart @@ -0,0 +1,82 @@ +import 'package:agrilink_vocpro/core/constant/app_theme.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'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class NitrogenScreen extends StatelessWidget { + const NitrogenScreen({super.key, this.nitrogen = 0.0}); + + final double nitrogen; + double get value => nitrogen; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Nitrogen', style: AppTheme.labelMedium), + centerTitle: true, + backgroundColor: Colors.white, + scrolledUnderElevation: 0, + actions: const [ + Padding( + padding: EdgeInsets.only(right: 16), + child: Icon( + CupertinoIcons.eyedropper, + color: Colors.blue, + ), + ) + ], + ), + body: Center( + child: ListView( + padding: EdgeInsets.all(16.w), + children: [ + SizedBox(height: 32.h), + Column( + children: [ + Icon( + CupertinoIcons.eyedropper, + size: 64.r, + color: Colors.blue, + ), + Text('$value µS/cm', style: AppTheme.headline1), + ], + ), + SizedBox(height: 32.h), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Nitrogen', + style: AppTheme.labelMedium, + textAlign: TextAlign.center, + ), + IconButton( + iconSize: 20.r, + color: Colors.blue, + onPressed: () {}, + icon: const Icon(BootstrapIcons.info_circle)) + ], + ), + SizedBox(height: 16.h), + const Text('Grafik'), + SizedBox(height: 16.h), + AspectRatio( + aspectRatio: 1.6.h, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16.w), + border: Border.all(color: Colors.grey.shade300, width: 1.w), + ), + child: const GarphicWidget(), + ), + ) + ], + ), + ), + ); + } +} 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 a54000e..85ea0d7 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 @@ -24,8 +24,8 @@ class PhScreen extends StatelessWidget { Padding( padding: EdgeInsets.only(right: 16), child: Icon( - BootstrapIcons.thermometer_half, - color: Colors.red, + BootstrapIcons.pie_chart, + color: Colors.orange, ), ) ], @@ -58,105 +58,105 @@ class PhScreen extends StatelessWidget { ], ), SizedBox(height: 16.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Container( - height: 100.h, - width: 100.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - color: Colors.blue.withOpacity(0.1), - border: Border.all( - color: Colors.blue, - width: 2, - ), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('Low', - style: AppTheme.labelMedium - .copyWith(color: Colors.blue)), - // SizedBox(height: 8.h), - // const Icon( - // BootstrapIcons.thermometer_low, - // color: Colors.blue, - // ), - SizedBox(height: 8.h), - Text( - '<20°C', - style: AppTheme.labelMedium, - textAlign: TextAlign.center, - ), - ], - ), - ), - Container( - height: 100.h, - width: 100.w, - decoration: BoxDecoration( - color: Colors.green.withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: Colors.green, - width: 2, - ), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('Ideal', - style: AppTheme.labelMedium - .copyWith(color: Colors.green)), - // SizedBox(height: 8.h), - // const Icon( - // BootstrapIcons.thermometer_half, - // color: Colors.green, - // ), - SizedBox(height: 8.h), - Text( - '20-30°C', - style: AppTheme.labelMedium, - textAlign: TextAlign.center, - ), - ], - ), - ), - Container( - height: 100.h, - width: 100.w, - decoration: BoxDecoration( - color: Colors.orange.withOpacity(0.1), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: Colors.orange.shade800, - width: 2, - ), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text('high', - style: AppTheme.labelMedium - .copyWith(color: Colors.orange)), - // SizedBox(height: 8.h), - // const Icon( - // BootstrapIcons.thermometer_high, - // color: Colors.orange, - // ), - SizedBox(height: 8.h), - Text( - '>30°C', - style: AppTheme.labelMedium, - textAlign: TextAlign.center, - ), - ], - ), - ), - ], - ), - SizedBox(height: 16.h), + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceAround, + // children: [ + // Container( + // height: 100.h, + // width: 100.w, + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(16), + // color: Colors.blue.withOpacity(0.1), + // border: Border.all( + // color: Colors.blue, + // width: 2, + // ), + // ), + // child: Column( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Text('Low', + // style: AppTheme.labelMedium + // .copyWith(color: Colors.blue)), + // // SizedBox(height: 8.h), + // // const Icon( + // // BootstrapIcons.thermometer_low, + // // color: Colors.blue, + // // ), + // SizedBox(height: 8.h), + // Text( + // '<20°C', + // style: AppTheme.labelMedium, + // textAlign: TextAlign.center, + // ), + // ], + // ), + // ), + // Container( + // height: 100.h, + // width: 100.w, + // decoration: BoxDecoration( + // color: Colors.green.withOpacity(0.1), + // borderRadius: BorderRadius.circular(16), + // border: Border.all( + // color: Colors.green, + // width: 2, + // ), + // ), + // child: Column( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Text('Ideal', + // style: AppTheme.labelMedium + // .copyWith(color: Colors.green)), + // // SizedBox(height: 8.h), + // // const Icon( + // // BootstrapIcons.thermometer_half, + // // color: Colors.green, + // // ), + // SizedBox(height: 8.h), + // Text( + // '20-30°C', + // style: AppTheme.labelMedium, + // textAlign: TextAlign.center, + // ), + // ], + // ), + // ), + // Container( + // height: 100.h, + // width: 100.w, + // decoration: BoxDecoration( + // color: Colors.orange.withOpacity(0.1), + // borderRadius: BorderRadius.circular(16), + // border: Border.all( + // color: Colors.orange.shade800, + // width: 2, + // ), + // ), + // child: Column( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Text('high', + // style: AppTheme.labelMedium + // .copyWith(color: Colors.orange)), + // // SizedBox(height: 8.h), + // // const Icon( + // // BootstrapIcons.thermometer_high, + // // color: Colors.orange, + // // ), + // SizedBox(height: 8.h), + // Text( + // '>30°C', + // style: AppTheme.labelMedium, + // textAlign: TextAlign.center, + // ), + // ], + // ), + // ), + // ], + // ), + // SizedBox(height: 16.h), const Text('Grafik'), SizedBox(height: 16.h), AspectRatio( diff --git a/agrilink_vocpro/lib/features/home/pages/ph/widget/ph_bar_pointer.dart b/agrilink_vocpro/lib/features/home/pages/ph/widget/ph_bar_pointer.dart index 4d9e804..60f5f39 100644 --- a/agrilink_vocpro/lib/features/home/pages/ph/widget/ph_bar_pointer.dart +++ b/agrilink_vocpro/lib/features/home/pages/ph/widget/ph_bar_pointer.dart @@ -1,5 +1,4 @@ import 'package:agrilink_vocpro/core/constant/app_theme.dart'; -import 'package:bootstrap_icons/bootstrap_icons.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; 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 new file mode 100644 index 0000000..d273827 --- /dev/null +++ b/agrilink_vocpro/lib/features/home/pages/phosphorus/view/phosphorus_screen.dart @@ -0,0 +1,82 @@ +import 'package:agrilink_vocpro/core/constant/app_theme.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'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class PhosphorusScreen extends StatelessWidget { + const PhosphorusScreen({super.key, this.phosphorus = 0.0}); + + final double phosphorus; + double get value => phosphorus; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Phosphorus', style: AppTheme.labelMedium), + centerTitle: true, + backgroundColor: Colors.white, + scrolledUnderElevation: 0, + actions: const [ + Padding( + padding: EdgeInsets.only(right: 16), + child: Icon( + CupertinoIcons.eyedropper, + color: Colors.blue, + ), + ) + ], + ), + body: Center( + child: ListView( + padding: EdgeInsets.all(16.w), + children: [ + SizedBox(height: 32.h), + Column( + children: [ + Icon( + CupertinoIcons.eyedropper, + size: 64.r, + color: Colors.blue, + ), + Text('$value ppm', style: AppTheme.headline1), + ], + ), + SizedBox(height: 32.h), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Fosfor', + style: AppTheme.labelMedium, + textAlign: TextAlign.center, + ), + IconButton( + iconSize: 20.r, + color: Colors.blue, + onPressed: () {}, + icon: const Icon(BootstrapIcons.info_circle)) + ], + ), + SizedBox(height: 16.h), + const Text('Grafik'), + SizedBox(height: 16.h), + AspectRatio( + aspectRatio: 1.6.h, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16.w), + border: Border.all(color: Colors.grey.shade300, width: 1.w), + ), + child: const GarphicWidget(), + ), + ) + ], + ), + ), + ); + } +} 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 new file mode 100644 index 0000000..d38d726 --- /dev/null +++ b/agrilink_vocpro/lib/features/home/pages/potassium/view/potassium_screen.dart @@ -0,0 +1,82 @@ +import 'package:agrilink_vocpro/core/constant/app_theme.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'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; + +class PotassiumScreen extends StatelessWidget { + const PotassiumScreen({super.key, this.potassium = 0.0}); + + final double potassium; + double get value => potassium; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Potassium', style: AppTheme.labelMedium), + centerTitle: true, + backgroundColor: Colors.white, + scrolledUnderElevation: 0, + actions: const [ + Padding( + padding: EdgeInsets.only(right: 16), + child: Icon( + CupertinoIcons.eyedropper, + color: Colors.green, + ), + ) + ], + ), + body: Center( + child: ListView( + padding: EdgeInsets.all(16.w), + children: [ + SizedBox(height: 32.h), + Column( + children: [ + Icon( + CupertinoIcons.eyedropper, + size: 64.r, + color: Colors.green, + ), + Text('$value ppm', style: AppTheme.headline1), + ], + ), + SizedBox(height: 32.h), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Kalium', + style: AppTheme.labelMedium, + textAlign: TextAlign.center, + ), + IconButton( + iconSize: 20.r, + color: Colors.blue, + onPressed: () {}, + icon: const Icon(BootstrapIcons.info_circle)) + ], + ), + SizedBox(height: 16.h), + const Text('Grafik'), + SizedBox(height: 16.h), + AspectRatio( + aspectRatio: 1.6.h, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16.w), + border: Border.all(color: Colors.grey.shade300, width: 1.w), + ), + child: const GarphicWidget(), + ), + ) + ], + ), + ), + ); + } +} 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 3847ae9..05de5ca 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 @@ -6,7 +6,10 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:gauge_indicator/gauge_indicator.dart'; class SoilMoistureScreen extends StatelessWidget { - const SoilMoistureScreen({super.key}); + const SoilMoistureScreen({super.key, this.moisture = 0}); + + final double moisture; + double get value => moisture; @override Widget build(BuildContext context) { @@ -55,7 +58,7 @@ class SoilMoistureScreen extends StatelessWidget { child: AnimatedRadialGauge( duration: const Duration(seconds: 3), curve: Curves.easeOut, - value: 60, + value: value, axis: GaugeAxis( degrees: 360, min: 0, 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 new file mode 100644 index 0000000..5dae429 --- /dev/null +++ b/agrilink_vocpro/lib/features/home/pages/soil_temperature/view/soil_temperature_screen.dart @@ -0,0 +1,256 @@ +import 'package:agrilink_vocpro/core/constant/app_constant.dart'; +import 'package:agrilink_vocpro/core/constant/app_theme.dart'; +import 'package:agrilink_vocpro/features/home/widgets/graphic_widget.dart'; +import 'package:bootstrap_icons/bootstrap_icons.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:gauge_indicator/gauge_indicator.dart'; + +class SoilTemperatureScreen extends StatelessWidget { + const SoilTemperatureScreen({super.key, this.temperature = 0}); + + final double temperature; + double get value => temperature; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Soil Temperature', style: AppTheme.labelMedium), + centerTitle: true, + backgroundColor: Colors.white, + scrolledUnderElevation: 0, + actions: const [ + Padding( + padding: EdgeInsets.only(right: 16), + child: Icon( + BootstrapIcons.water, + color: Colors.green, + ), + ) + ], + ), + body: SafeArea( + child: ListView( + padding: EdgeInsets.all(16.w), + children: [ + SizedBox( + height: MediaQuery.of(context).size.height * 0.05, + ), + SizedBox( + height: 240.h, + child: Stack( + fit: StackFit.expand, + children: [ + Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: 80.h, + ), + const Icon(BootstrapIcons.water, + size: 32, color: Colors.green), + Text( + '${value.toStringAsFixed(0)}°C', // Animated percentage text + style: const TextStyle( + fontSize: 28, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ], + ), + ), + AnimatedRadialGauge( + duration: const Duration(seconds: 2), + curve: Curves.easeOut, + value: value, + axis: GaugeAxis( + degrees: 240, + min: 0, + max: 56.7, + style: GaugeAxisStyle( + background: Colors.grey.shade100, + thickness: 50, + ), + progressBar: const GaugeBasicProgressBar( + gradient: GaugeAxisGradient(colors: [ + Colors.blue, + Colors.orange, + ]), + ), + ), + ), + ], + ), + ), + const SizedBox(height: 16), + const SizedBox(height: 16), + 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), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Container( + height: 100.h, + width: 100.w, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: Colors.blue.withOpacity(0.1), + border: Border.all( + color: Colors.blue, + width: 2, + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Low', + style: AppTheme.labelMedium + .copyWith(color: Colors.blue)), + // SizedBox(height: 8.h), + // const Icon( + // BootstrapIcons.thermometer_low, + // color: Colors.blue, + // ), + SizedBox(height: 8.h), + Text( + '<20°C', + style: AppTheme.labelMedium, + textAlign: TextAlign.center, + ), + ], + ), + ), + Container( + height: 100.h, + width: 100.w, + decoration: BoxDecoration( + color: Colors.green.withOpacity(0.1), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: Colors.green, + width: 2, + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('Ideal', + style: AppTheme.labelMedium + .copyWith(color: Colors.green)), + // SizedBox(height: 8.h), + // const Icon( + // BootstrapIcons.thermometer_half, + // color: Colors.green, + // ), + SizedBox(height: 8.h), + Text( + '20-30°C', + style: AppTheme.labelMedium, + textAlign: TextAlign.center, + ), + ], + ), + ), + Container( + height: 100.h, + width: 100.w, + decoration: BoxDecoration( + color: Colors.orange.withOpacity(0.1), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: Colors.orange.shade800, + width: 2, + ), + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('high', + style: AppTheme.labelMedium + .copyWith(color: Colors.orange)), + // SizedBox(height: 8.h), + // const Icon( + // BootstrapIcons.thermometer_high, + // color: Colors.orange, + // ), + SizedBox(height: 8.h), + Text( + '>30°C', + style: AppTheme.labelMedium, + textAlign: TextAlign.center, + ), + ], + ), + ), + ], + ), + SizedBox(height: 16.h), + const Text('Grafik'), + SizedBox(height: 16.h), + AspectRatio( + aspectRatio: 1.6.h, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16.w), + border: Border.all(color: Colors.grey.shade300, width: 1.w), + ), + child: const GarphicWidget(), + ), + ) + ], + ), + ), + ); + } + + 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 fe9c134..3340242 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 @@ -6,9 +6,10 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:gauge_indicator/gauge_indicator.dart'; class TemperatureScreen extends StatelessWidget { - const TemperatureScreen({super.key}); + const TemperatureScreen({super.key, this.temperature = 0}); - double get value => 29; + final double temperature; + double get value => temperature; @override Widget build(BuildContext context) { 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 43b7a29..015f729 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 @@ -1,7 +1,6 @@ import 'package:agrilink_vocpro/core/constant/app_color.dart'; import 'package:agrilink_vocpro/core/route/app_route.dart'; import 'package:agrilink_vocpro/core/state/result_state.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/widgets/censor_item_loading_widgets.dart'; import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart'; @@ -59,7 +58,7 @@ class ListDataFromCensorDht extends StatelessWidget { iconColor: Colors.white, censorIdentifier: 'NPK 1', onTap: () async { - context.push(AppRoute.humidity, extra: '60'); + await context.push('${AppRoute.humidity}/60'); }, ), DataDisplayerWidget( @@ -70,29 +69,34 @@ class ListDataFromCensorDht extends StatelessWidget { icon: BootstrapIcons.thermometer_half, color: Colors.white, onTap: () async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const TemperatureScreen())); + await context.push('${AppRoute.temperature}/28'); }, ), DataDisplayerWidget( title: 'Light', subtitle: 'intensitas cahaya', - value: '1000', + value: '320.5', unit: 'lux', icon: BootstrapIcons.sun, color: Colors.white, onTap: () async { - context.push('${AppRoute.light}/300'); + await context.push('${AppRoute.light}/320.5'); }, ), ], ); case ResultState.noData: - return const Center(child: Text('No Data')); + return Center( + child: Image.asset( + 'assets/images/no_data_image.png', + width: 200.w, + )); case ResultState.error: - return const Center(child: Text('Error')); + return Center( + child: Image.asset( + 'assets/images/error_image.png', + width: 200.w, + )); case ResultState.initial: return const SizedBox.shrink(); default: diff --git a/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_npk1.dart b/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_npk1.dart index d3db9cd..0249cdd 100644 --- a/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_npk1.dart +++ b/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_npk1.dart @@ -1,8 +1,6 @@ import 'package:agrilink_vocpro/core/constant/app_color.dart'; import 'package:agrilink_vocpro/core/route/app_route.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/widgets/censor_item_loading_widgets.dart'; import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart'; @@ -59,10 +57,7 @@ class ListDataFromCensorNpk1 extends StatelessWidget { iconColor: Colors.white, censorIdentifier: censorIdentifier, onTap: () async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const TemperatureScreen())); + await context.push('${AppRoute.soilTemperature}/28'); }, ), DataDisplayerWidget( @@ -74,12 +69,7 @@ class ListDataFromCensorNpk1 extends StatelessWidget { color: Colors.white, censorIdentifier: censorIdentifier, onTap: () async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const SoilMoistureScreen(), - ), - ); + await context.push('${AppRoute.soilMoisture}/40'); }, ), DataDisplayerWidget( @@ -103,7 +93,7 @@ class ListDataFromCensorNpk1 extends StatelessWidget { color: Colors.white, censorIdentifier: censorIdentifier, onTap: () async { - context.push(AppRoute.humidity, extra: '60'); + await context.push('${AppRoute.conductivity}/234'); }, ), DataDisplayerWidget( @@ -113,7 +103,9 @@ class ListDataFromCensorNpk1 extends StatelessWidget { unit: 'ppm', icon: CupertinoIcons.eyedropper, color: Colors.white, - onTap: () {}, + onTap: () async { + await context.push('${AppRoute.nitrogen}/30'); + }, ), DataDisplayerWidget( title: 'Potassium', @@ -122,7 +114,9 @@ class ListDataFromCensorNpk1 extends StatelessWidget { unit: 'ppm', icon: CupertinoIcons.eyedropper, color: Colors.white, - onTap: () {}, + onTap: () async { + await context.push('${AppRoute.potassium}/20'); + }, ), DataDisplayerWidget( title: 'Phosphorus', @@ -131,14 +125,24 @@ class ListDataFromCensorNpk1 extends StatelessWidget { unit: 'ppm', icon: CupertinoIcons.eyedropper, color: Colors.white, - onTap: () {}, + onTap: () async { + await context.push('${AppRoute.phosphorus}/54'); + }, ), ], ); case ResultState.noData: - return const Center(child: Text('No Data')); + return Center( + child: Image.asset( + 'assets/images/no_data_image.png', + width: 200.w, + )); case ResultState.error: - return const Center(child: Text('Error')); + return Center( + child: Image.asset( + 'assets/images/error_image.png', + width: 200.w, + )); default: return const SizedBox.shrink(); } diff --git a/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_npk2.dart b/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_npk2.dart index 71f5013..c59a3c4 100644 --- a/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_npk2.dart +++ b/agrilink_vocpro/lib/features/home/widgets/list_data_from_censor_npk2.dart @@ -1,13 +1,17 @@ import 'package:agrilink_vocpro/core/constant/app_color.dart'; import 'package:agrilink_vocpro/core/route/app_route.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/widgets/censor_item_loading_widgets.dart'; import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.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'; import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; class ListDataFromCensorNpk2 extends StatelessWidget { const ListDataFromCensorNpk2({ @@ -17,100 +21,133 @@ class ListDataFromCensorNpk2 extends StatelessWidget { @override Widget build(BuildContext context) { const String censorIdentifier = 'NPK 1'; - return GridView( - padding: EdgeInsets.all(16.r), - shrinkWrap: true, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 16.r, - mainAxisSpacing: 16.r, - childAspectRatio: 0.9, - ), - children: [ - DataDisplayerWidget( - title: 'Temperature', - subtitle: 'Suhu tanah', - value: '28', - unit: '°C', - icon: BootstrapIcons.thermometer_half, - textColor: Colors.white, - color: AppColor.secondary, - iconColor: Colors.white, - censorIdentifier: censorIdentifier, - onTap: () async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const TemperatureScreen())); - }, - ), - DataDisplayerWidget( - title: 'Soil Moisture', - subtitle: 'kelembaban tanah', - value: '40', - unit: '%', - icon: Icons.water_outlined, - color: Colors.white, - censorIdentifier: censorIdentifier, - onTap: () async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const SoilMoistureScreen(), + return Consumer(builder: (context, provider, child) { + switch (provider.dataState) { + case ResultState.loading: + return GridView( + padding: EdgeInsets.all(16.r), + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 16.r, + mainAxisSpacing: 16.r, + childAspectRatio: 0.9, + ), + children: [ + for (int i = 0; i < 4; i++) const CensorItemLoadingWidgets(), + ], + ); + case ResultState.hasData: + return GridView( + padding: EdgeInsets.all(16.r), + shrinkWrap: true, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 16.r, + mainAxisSpacing: 16.r, + childAspectRatio: 0.9, + ), + children: [ + DataDisplayerWidget( + title: 'Temperature', + subtitle: 'Suhu tanah', + value: '28', + unit: '°C', + icon: BootstrapIcons.thermometer_half, + textColor: Colors.white, + color: AppColor.secondary, + iconColor: Colors.white, + censorIdentifier: censorIdentifier, + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const TemperatureScreen())); + }, ), - ); - }, - ), - DataDisplayerWidget( - title: 'Acid Level (PH)', - subtitle: 'tingkat keasaman', - value: '6.5', - unit: 'pH', - icon: BootstrapIcons.pie_chart, - color: Colors.white, - censorIdentifier: censorIdentifier, - onTap: () {}, - ), - DataDisplayerWidget( - title: 'Conductivity', - subtitle: 'Daya Arus Listrik', - value: '234', - unit: 'µS/cm', - icon: Icons.electric_bolt, - color: Colors.white, - censorIdentifier: censorIdentifier, - onTap: () async { - context.push(AppRoute.humidity, extra: '60'); - }, - ), - DataDisplayerWidget( - title: 'Nitrogen', - subtitle: 'Kadar Nitrogen', - value: '30', - unit: 'ppm', - icon: CupertinoIcons.eyedropper, - color: Colors.white, - onTap: () {}, - ), - DataDisplayerWidget( - title: 'Potassium', - subtitle: 'Kadar kalium', - value: '20', - unit: 'ppm', - icon: CupertinoIcons.eyedropper, - color: Colors.white, - onTap: () {}, - ), - DataDisplayerWidget( - title: 'Phosphorus', - subtitle: 'Kadar Fosfor', - value: '54', - unit: 'ppm', - icon: CupertinoIcons.eyedropper, - color: Colors.white, - onTap: () {}, - ), - ], - ); + DataDisplayerWidget( + title: 'Soil Moisture', + subtitle: 'kelembaban tanah', + value: '40', + unit: '%', + icon: Icons.water_outlined, + color: Colors.white, + censorIdentifier: censorIdentifier, + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const SoilMoistureScreen(), + ), + ); + }, + ), + DataDisplayerWidget( + title: 'Acid Level (PH)', + subtitle: 'tingkat keasaman', + value: '6.5', + unit: 'pH', + icon: BootstrapIcons.pie_chart, + color: Colors.white, + censorIdentifier: censorIdentifier, + onTap: () {}, + ), + DataDisplayerWidget( + title: 'Conductivity', + subtitle: 'Daya Arus Listrik', + value: '234', + unit: 'µS/cm', + icon: Icons.electric_bolt, + color: Colors.white, + censorIdentifier: censorIdentifier, + onTap: () async { + context.push(AppRoute.humidity, extra: '60'); + }, + ), + DataDisplayerWidget( + title: 'Nitrogen', + subtitle: 'Kadar Nitrogen', + value: '30', + unit: 'ppm', + icon: CupertinoIcons.eyedropper, + color: Colors.white, + onTap: () {}, + ), + DataDisplayerWidget( + title: 'Potassium', + subtitle: 'Kadar kalium', + value: '20', + unit: 'ppm', + icon: CupertinoIcons.eyedropper, + color: Colors.white, + onTap: () {}, + ), + DataDisplayerWidget( + title: 'Phosphorus', + subtitle: 'Kadar Fosfor', + value: '54', + unit: 'ppm', + icon: CupertinoIcons.eyedropper, + color: Colors.white, + onTap: () {}, + ), + ], + ); + case ResultState.noData: + return Center( + child: Image.asset( + 'assets/images/no_data_image.png', + width: 200.w, + )); + case ResultState.error: + return Center( + child: Image.asset( + 'assets/images/error_image.png', + width: 200.w, + )); + default: + return const SizedBox.shrink(); + } + }); } } diff --git a/agrilink_vocpro/lib/features/setting/view/setting_screen.dart b/agrilink_vocpro/lib/features/setting/view/setting_screen.dart index 3b37841..ffcef03 100644 --- a/agrilink_vocpro/lib/features/setting/view/setting_screen.dart +++ b/agrilink_vocpro/lib/features/setting/view/setting_screen.dart @@ -1,10 +1,7 @@ -import 'dart:io'; - import 'package:agrilink_vocpro/core/constant/app_color.dart'; import 'package:agrilink_vocpro/core/constant/app_theme.dart'; import 'package:agrilink_vocpro/core/route/app_route.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'; import 'package:go_router/go_router.dart';