feat: add detail screen (npk sensor)

This commit is contained in:
Syaroful 2024-10-08 09:23:48 +07:00
parent 10880bddfd
commit fc4350f1dd
25 changed files with 1130 additions and 333 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -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.';
}

View File

@ -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';
}

View File

@ -1,8 +1,15 @@
import 'package:agrilink_vocpro/features/auth/view/login_screen.dart'; 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/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/humidity/view/humidity_screen.dart';
import 'package:agrilink_vocpro/features/home/pages/light/view/light_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/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:agrilink_vocpro/features/splash/view/splash_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -15,12 +22,15 @@ class AppRoute {
static const String profile = '/profile'; static const String profile = '/profile';
static const String setting = '/setting'; static const String setting = '/setting';
static const String humidity = '/dashboard/humidity'; static const String humidity = '/dashboard/humidity';
static const String temperature = '/temperature'; static const String temperature = '/dashboard/temperature';
static const String soil = '/soil'; static const String soilTemperature = '/dashboard/soil_temperature';
static const String soilMoisture = '/dashboard/soil_moisture';
static const String light = '/dashboard/light'; static const String light = '/dashboard/light';
static const String ph = '/dashboard/ph'; static const String ph = '/dashboard/ph';
static const String water = '/water'; static const String conductivity = '/dashboard/conductivity';
static const String acidity = '/acidity'; static const String nitrogen = '/dashboard/nitrogen';
static const String phosphorus = '/dashboard/phosphorus';
static const String potassium = '/dashboard/potassium';
static final GoRouter router = GoRouter( static final GoRouter router = GoRouter(
initialLocation: root, initialLocation: root,
@ -35,35 +45,30 @@ class AppRoute {
path: login, path: login,
builder: (context, state) => const LoginScreen(), builder: (context, state) => const LoginScreen(),
), ),
//dashboard
GoRoute(
path: dashboard,
builder: (context, state) => const DashboardScreen(),
),
GoRoute( GoRoute(
path: dashboard, path: dashboard,
builder: (context, state) => const DashboardScreen(), builder: (context, state) => const DashboardScreen(),
routes: [ routes: [
GoRoute( // humidity
path: 'humidity', buildHumidityRoute(),
builder: (context, state) => const HumidityScreen(), // light intensity
), buildLightIntensityRoute(),
GoRoute( // temperature
path: 'light/:value', buildTemperatureRoute(),
builder: (context, state) { // ph
final double value = buildAcidityRoute(),
double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; // soil moisture
return LightScreen(lightIntensity: value); buildSoilTempRoute(),
}, // soil moisture
), buildSoilMoistureRoute(),
GoRoute( // conductivity
path: 'ph/:value', buildConductivityRoute(),
builder: (context, state) { // nitrogen
final double value = buildNitrogenRoute(),
double.tryParse(state.pathParameters['value'] ?? '') ?? 0.0; // phosphorus
return PhScreen(phValue: value); 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);
},
);
}
} }

View File

@ -1,5 +0,0 @@
import 'package:flutter/material.dart';
class CensorProvider extends ChangeNotifier {
Future<void> setupMqtt() async {}
}

View File

@ -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<void> getGreenHouseData() async {
try {} on DioException catch (e) {
if (kDebugMode) {
print(e);
}
rethrow;
}
}
}

View File

@ -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:agrilink_vocpro/core/state/result_state.dart';
import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_client.dart';
import 'package:mqtt_client/mqtt_server_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart';
@ -6,11 +9,11 @@ class MQTTService {
MqttServerClient? client; MqttServerClient? client;
Future<ResultState> setupMqtt() async { Future<ResultState> setupMqtt() async {
client = MqttServerClient('armadillo.rmq.cloudamqp.com', ''); client = MqttServerClient(AppConstant.mqttServer, '');
client!.port = 1883; client!.port = 1883;
client!.connectionMessage = MqttConnectMessage() client!.connectionMessage = MqttConnectMessage()
.authenticateAs('obyskxhx:obyskxhx', 'Fe_3_tBuwmc8vMMqT2hYiboTsBlBmPz1') .authenticateAs(AppConstant.mqttUsername, AppConstant.mqttPassword)
.withClientIdentifier('mobile_client_controller') .withClientIdentifier('mobile_client_controller')
.startClean() // reset session .startClean() // reset session
.withWillQos(MqttQos.atLeastOnce); .withWillQos(MqttQos.atLeastOnce);
@ -90,14 +93,14 @@ class MQTTService {
client!.updates!.listen( client!.updates!.listen(
(List<MqttReceivedMessage<MqttMessage?>>? messages) { (List<MqttReceivedMessage<MqttMessage?>>? messages) {
print('MQTT: Message received!'); print('MQTT: Subscribe Message received!');
if (messages != null && messages.isNotEmpty) { if (messages != null && messages.isNotEmpty) {
final MqttPublishMessage recMessage = final MqttPublishMessage recMessage =
messages[0].payload as MqttPublishMessage; messages[0].payload as MqttPublishMessage;
final String payload = MqttPublishPayload.bytesToStringAsString( final String payload = MqttPublishPayload.bytesToStringAsString(
recMessage.payload.message); recMessage.payload.message);
print( print(
'MQTT: Message received on topic ${messages[0].topic}: $payload'); 'MQTT: Subscribe Message received on topic ${messages[0].topic}: $payload');
if (payload == 'ON') { if (payload == 'ON') {
isActive = true; isActive = true;
@ -105,9 +108,11 @@ class MQTTService {
} else if (payload == 'OFF') { } else if (payload == 'OFF') {
isActive = false; isActive = false;
// Update UI atau provider untuk menandakan relay OFF // Update UI atau provider untuk menandakan relay OFF
} else {
print('MQTT: Invalid Subscribe message received');
} }
} else { } else {
print('MQTT: No messages received'); print('MQTT: No Subscribe messages received');
} }
}, },
); );
@ -122,4 +127,44 @@ class MQTTService {
return false; return false;
} }
} }
Future<ResultState> 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<MqttReceivedMessage<MqttMessage?>>? 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<String, dynamic> 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;
}
}
} }

View File

@ -1 +0,0 @@
class Service {}

View File

@ -25,14 +25,14 @@ class ControlProvider extends ChangeNotifier {
final result = await _mqttService.setupMqtt(); final result = await _mqttService.setupMqtt();
if (result == ResultState.hasData) { if (result == ResultState.hasData) {
mqttState = result; mqttState = result;
final result2 = await _mqttService.subscribeToTopic('relay1'); final result2 = await _mqttService.subscribeToRelayStatus();
if (result2 == true) { // if (result2 == true) {
subscribeState = ResultState.hasData; // subscribeState = ResultState.hasData;
_control_1 = true; // _control_1 = true;
} else { // } else {
subscribeState = ResultState.hasData; // subscribeState = ResultState.hasData;
_control_1 = false; // _control_1 = false;
} // }
} else { } else {
mqttState = ResultState.error; mqttState = ResultState.error;
} }

View File

@ -18,55 +18,40 @@ class ControlScreen extends StatelessWidget {
backgroundColor: Colors.white, backgroundColor: Colors.white,
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
), ),
body: Consumer<ControlProvider>(builder: (context, provider, child) { body: Consumer<ControlProvider>(
return SafeArea( builder: (context, provider, child) {
return SafeArea(
child: ListView( child: ListView(
children: [ children: [
Center( Center(
child: provider.mqttState == ResultState.loading child: provider.mqttState == ResultState.loading
? const CupertinoActivityIndicator() ? const CupertinoActivityIndicator()
: provider.mqttState == ResultState.hasData : provider.mqttState == ResultState.hasData
? const Text('Terhubung ke Broker') ? const Text('Terhubung ke Broker')
: const Text('Gagal 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...
],
));
}),
); );
} }
} }

View File

@ -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(),
),
)
],
),
),
);
}
}

View File

@ -9,7 +9,10 @@ import 'package:gauge_indicator/gauge_indicator.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class HumidityScreen extends StatelessWidget { class HumidityScreen extends StatelessWidget {
const HumidityScreen({super.key}); const HumidityScreen({super.key, this.humidity = 0});
final double humidity;
double get value => humidity;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -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(),
),
)
],
),
),
);
}
}

View File

@ -24,8 +24,8 @@ class PhScreen extends StatelessWidget {
Padding( Padding(
padding: EdgeInsets.only(right: 16), padding: EdgeInsets.only(right: 16),
child: Icon( child: Icon(
BootstrapIcons.thermometer_half, BootstrapIcons.pie_chart,
color: Colors.red, color: Colors.orange,
), ),
) )
], ],
@ -58,105 +58,105 @@ class PhScreen extends StatelessWidget {
], ],
), ),
SizedBox(height: 16.h), SizedBox(height: 16.h),
Row( // Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, // mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [ // children: [
Container( // Container(
height: 100.h, // height: 100.h,
width: 100.w, // width: 100.w,
decoration: BoxDecoration( // decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16), // borderRadius: BorderRadius.circular(16),
color: Colors.blue.withOpacity(0.1), // color: Colors.blue.withOpacity(0.1),
border: Border.all( // border: Border.all(
color: Colors.blue, // color: Colors.blue,
width: 2, // width: 2,
), // ),
), // ),
child: Column( // child: Column(
mainAxisAlignment: MainAxisAlignment.center, // mainAxisAlignment: MainAxisAlignment.center,
children: [ // children: [
Text('Low', // Text('Low',
style: AppTheme.labelMedium // style: AppTheme.labelMedium
.copyWith(color: Colors.blue)), // .copyWith(color: Colors.blue)),
// SizedBox(height: 8.h), // // SizedBox(height: 8.h),
// const Icon( // // const Icon(
// BootstrapIcons.thermometer_low, // // BootstrapIcons.thermometer_low,
// color: Colors.blue, // // color: Colors.blue,
// ), // // ),
SizedBox(height: 8.h), // SizedBox(height: 8.h),
Text( // Text(
'<20°C', // '<20°C',
style: AppTheme.labelMedium, // style: AppTheme.labelMedium,
textAlign: TextAlign.center, // textAlign: TextAlign.center,
), // ),
], // ],
), // ),
), // ),
Container( // Container(
height: 100.h, // height: 100.h,
width: 100.w, // width: 100.w,
decoration: BoxDecoration( // decoration: BoxDecoration(
color: Colors.green.withOpacity(0.1), // color: Colors.green.withOpacity(0.1),
borderRadius: BorderRadius.circular(16), // borderRadius: BorderRadius.circular(16),
border: Border.all( // border: Border.all(
color: Colors.green, // color: Colors.green,
width: 2, // width: 2,
), // ),
), // ),
child: Column( // child: Column(
mainAxisAlignment: MainAxisAlignment.center, // mainAxisAlignment: MainAxisAlignment.center,
children: [ // children: [
Text('Ideal', // Text('Ideal',
style: AppTheme.labelMedium // style: AppTheme.labelMedium
.copyWith(color: Colors.green)), // .copyWith(color: Colors.green)),
// SizedBox(height: 8.h), // // SizedBox(height: 8.h),
// const Icon( // // const Icon(
// BootstrapIcons.thermometer_half, // // BootstrapIcons.thermometer_half,
// color: Colors.green, // // color: Colors.green,
// ), // // ),
SizedBox(height: 8.h), // SizedBox(height: 8.h),
Text( // Text(
'20-30°C', // '20-30°C',
style: AppTheme.labelMedium, // style: AppTheme.labelMedium,
textAlign: TextAlign.center, // textAlign: TextAlign.center,
), // ),
], // ],
), // ),
), // ),
Container( // Container(
height: 100.h, // height: 100.h,
width: 100.w, // width: 100.w,
decoration: BoxDecoration( // decoration: BoxDecoration(
color: Colors.orange.withOpacity(0.1), // color: Colors.orange.withOpacity(0.1),
borderRadius: BorderRadius.circular(16), // borderRadius: BorderRadius.circular(16),
border: Border.all( // border: Border.all(
color: Colors.orange.shade800, // color: Colors.orange.shade800,
width: 2, // width: 2,
), // ),
), // ),
child: Column( // child: Column(
mainAxisAlignment: MainAxisAlignment.center, // mainAxisAlignment: MainAxisAlignment.center,
children: [ // children: [
Text('high', // Text('high',
style: AppTheme.labelMedium // style: AppTheme.labelMedium
.copyWith(color: Colors.orange)), // .copyWith(color: Colors.orange)),
// SizedBox(height: 8.h), // // SizedBox(height: 8.h),
// const Icon( // // const Icon(
// BootstrapIcons.thermometer_high, // // BootstrapIcons.thermometer_high,
// color: Colors.orange, // // color: Colors.orange,
// ), // // ),
SizedBox(height: 8.h), // SizedBox(height: 8.h),
Text( // Text(
'>30°C', // '>30°C',
style: AppTheme.labelMedium, // style: AppTheme.labelMedium,
textAlign: TextAlign.center, // textAlign: TextAlign.center,
), // ),
], // ],
), // ),
), // ),
], // ],
), // ),
SizedBox(height: 16.h), // SizedBox(height: 16.h),
const Text('Grafik'), const Text('Grafik'),
SizedBox(height: 16.h), SizedBox(height: 16.h),
AspectRatio( AspectRatio(

View File

@ -1,5 +1,4 @@
import 'package:agrilink_vocpro/core/constant/app_theme.dart'; import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:bootstrap_icons/bootstrap_icons.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';

View File

@ -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(),
),
)
],
),
),
);
}
}

View File

@ -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(),
),
)
],
),
),
);
}
}

View File

@ -6,7 +6,10 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:gauge_indicator/gauge_indicator.dart'; import 'package:gauge_indicator/gauge_indicator.dart';
class SoilMoistureScreen extends StatelessWidget { class SoilMoistureScreen extends StatelessWidget {
const SoilMoistureScreen({super.key}); const SoilMoistureScreen({super.key, this.moisture = 0});
final double moisture;
double get value => moisture;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -55,7 +58,7 @@ class SoilMoistureScreen extends StatelessWidget {
child: AnimatedRadialGauge( child: AnimatedRadialGauge(
duration: const Duration(seconds: 3), duration: const Duration(seconds: 3),
curve: Curves.easeOut, curve: Curves.easeOut,
value: 60, value: value,
axis: GaugeAxis( axis: GaugeAxis(
degrees: 360, degrees: 360,
min: 0, min: 0,

View File

@ -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<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

@ -6,9 +6,10 @@ import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:gauge_indicator/gauge_indicator.dart'; import 'package:gauge_indicator/gauge_indicator.dart';
class TemperatureScreen extends StatelessWidget { 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -1,7 +1,6 @@
import 'package:agrilink_vocpro/core/constant/app_color.dart'; import 'package:agrilink_vocpro/core/constant/app_color.dart';
import 'package:agrilink_vocpro/core/route/app_route.dart'; import 'package:agrilink_vocpro/core/route/app_route.dart';
import 'package:agrilink_vocpro/core/state/result_state.dart'; import 'package:agrilink_vocpro/core/state/result_state.dart';
import 'package:agrilink_vocpro/features/home/pages/temperature/view/temperature_screen.dart';
import 'package:agrilink_vocpro/features/home/provider/home_provider.dart'; import 'package:agrilink_vocpro/features/home/provider/home_provider.dart';
import 'package:agrilink_vocpro/features/home/widgets/censor_item_loading_widgets.dart'; import 'package:agrilink_vocpro/features/home/widgets/censor_item_loading_widgets.dart';
import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart'; import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart';
@ -59,7 +58,7 @@ class ListDataFromCensorDht extends StatelessWidget {
iconColor: Colors.white, iconColor: Colors.white,
censorIdentifier: 'NPK 1', censorIdentifier: 'NPK 1',
onTap: () async { onTap: () async {
context.push(AppRoute.humidity, extra: '60'); await context.push('${AppRoute.humidity}/60');
}, },
), ),
DataDisplayerWidget( DataDisplayerWidget(
@ -70,29 +69,34 @@ class ListDataFromCensorDht extends StatelessWidget {
icon: BootstrapIcons.thermometer_half, icon: BootstrapIcons.thermometer_half,
color: Colors.white, color: Colors.white,
onTap: () async { onTap: () async {
await Navigator.push( await context.push('${AppRoute.temperature}/28');
context,
MaterialPageRoute(
builder: (context) => const TemperatureScreen()));
}, },
), ),
DataDisplayerWidget( DataDisplayerWidget(
title: 'Light', title: 'Light',
subtitle: 'intensitas cahaya', subtitle: 'intensitas cahaya',
value: '1000', value: '320.5',
unit: 'lux', unit: 'lux',
icon: BootstrapIcons.sun, icon: BootstrapIcons.sun,
color: Colors.white, color: Colors.white,
onTap: () async { onTap: () async {
context.push('${AppRoute.light}/300'); await context.push('${AppRoute.light}/320.5');
}, },
), ),
], ],
); );
case ResultState.noData: 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: 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: case ResultState.initial:
return const SizedBox.shrink(); return const SizedBox.shrink();
default: default:

View File

@ -1,8 +1,6 @@
import 'package:agrilink_vocpro/core/constant/app_color.dart'; import 'package:agrilink_vocpro/core/constant/app_color.dart';
import 'package:agrilink_vocpro/core/route/app_route.dart'; import 'package:agrilink_vocpro/core/route/app_route.dart';
import 'package:agrilink_vocpro/core/state/result_state.dart'; import 'package:agrilink_vocpro/core/state/result_state.dart';
import 'package:agrilink_vocpro/features/home/pages/soil_moisture/view/soil_moisture_screen.dart';
import 'package:agrilink_vocpro/features/home/pages/temperature/view/temperature_screen.dart';
import 'package:agrilink_vocpro/features/home/provider/home_provider.dart'; import 'package:agrilink_vocpro/features/home/provider/home_provider.dart';
import 'package:agrilink_vocpro/features/home/widgets/censor_item_loading_widgets.dart'; import 'package:agrilink_vocpro/features/home/widgets/censor_item_loading_widgets.dart';
import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart'; import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart';
@ -59,10 +57,7 @@ class ListDataFromCensorNpk1 extends StatelessWidget {
iconColor: Colors.white, iconColor: Colors.white,
censorIdentifier: censorIdentifier, censorIdentifier: censorIdentifier,
onTap: () async { onTap: () async {
await Navigator.push( await context.push('${AppRoute.soilTemperature}/28');
context,
MaterialPageRoute(
builder: (context) => const TemperatureScreen()));
}, },
), ),
DataDisplayerWidget( DataDisplayerWidget(
@ -74,12 +69,7 @@ class ListDataFromCensorNpk1 extends StatelessWidget {
color: Colors.white, color: Colors.white,
censorIdentifier: censorIdentifier, censorIdentifier: censorIdentifier,
onTap: () async { onTap: () async {
await Navigator.push( await context.push('${AppRoute.soilMoisture}/40');
context,
MaterialPageRoute(
builder: (context) => const SoilMoistureScreen(),
),
);
}, },
), ),
DataDisplayerWidget( DataDisplayerWidget(
@ -103,7 +93,7 @@ class ListDataFromCensorNpk1 extends StatelessWidget {
color: Colors.white, color: Colors.white,
censorIdentifier: censorIdentifier, censorIdentifier: censorIdentifier,
onTap: () async { onTap: () async {
context.push(AppRoute.humidity, extra: '60'); await context.push('${AppRoute.conductivity}/234');
}, },
), ),
DataDisplayerWidget( DataDisplayerWidget(
@ -113,7 +103,9 @@ class ListDataFromCensorNpk1 extends StatelessWidget {
unit: 'ppm', unit: 'ppm',
icon: CupertinoIcons.eyedropper, icon: CupertinoIcons.eyedropper,
color: Colors.white, color: Colors.white,
onTap: () {}, onTap: () async {
await context.push('${AppRoute.nitrogen}/30');
},
), ),
DataDisplayerWidget( DataDisplayerWidget(
title: 'Potassium', title: 'Potassium',
@ -122,7 +114,9 @@ class ListDataFromCensorNpk1 extends StatelessWidget {
unit: 'ppm', unit: 'ppm',
icon: CupertinoIcons.eyedropper, icon: CupertinoIcons.eyedropper,
color: Colors.white, color: Colors.white,
onTap: () {}, onTap: () async {
await context.push('${AppRoute.potassium}/20');
},
), ),
DataDisplayerWidget( DataDisplayerWidget(
title: 'Phosphorus', title: 'Phosphorus',
@ -131,14 +125,24 @@ class ListDataFromCensorNpk1 extends StatelessWidget {
unit: 'ppm', unit: 'ppm',
icon: CupertinoIcons.eyedropper, icon: CupertinoIcons.eyedropper,
color: Colors.white, color: Colors.white,
onTap: () {}, onTap: () async {
await context.push('${AppRoute.phosphorus}/54');
},
), ),
], ],
); );
case ResultState.noData: 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: case ResultState.error:
return const Center(child: Text('Error')); return Center(
child: Image.asset(
'assets/images/error_image.png',
width: 200.w,
));
default: default:
return const SizedBox.shrink(); return const SizedBox.shrink();
} }

View File

@ -1,13 +1,17 @@
import 'package:agrilink_vocpro/core/constant/app_color.dart'; import 'package:agrilink_vocpro/core/constant/app_color.dart';
import 'package:agrilink_vocpro/core/route/app_route.dart'; import 'package:agrilink_vocpro/core/route/app_route.dart';
import 'package:agrilink_vocpro/core/state/result_state.dart';
import 'package:agrilink_vocpro/features/home/pages/soil_moisture/view/soil_moisture_screen.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/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:agrilink_vocpro/features/home/widgets/data_display_widget.dart';
import 'package:bootstrap_icons/bootstrap_icons.dart'; import 'package:bootstrap_icons/bootstrap_icons.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
class ListDataFromCensorNpk2 extends StatelessWidget { class ListDataFromCensorNpk2 extends StatelessWidget {
const ListDataFromCensorNpk2({ const ListDataFromCensorNpk2({
@ -17,100 +21,133 @@ class ListDataFromCensorNpk2 extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
const String censorIdentifier = 'NPK 1'; const String censorIdentifier = 'NPK 1';
return GridView( return Consumer<HomeProvider>(builder: (context, provider, child) {
padding: EdgeInsets.all(16.r), switch (provider.dataState) {
shrinkWrap: true, case ResultState.loading:
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( return GridView(
crossAxisCount: 2, padding: EdgeInsets.all(16.r),
crossAxisSpacing: 16.r, shrinkWrap: true,
mainAxisSpacing: 16.r, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 0.9, crossAxisCount: 2,
), crossAxisSpacing: 16.r,
children: [ mainAxisSpacing: 16.r,
DataDisplayerWidget( childAspectRatio: 0.9,
title: 'Temperature', ),
subtitle: 'Suhu tanah', children: [
value: '28', for (int i = 0; i < 4; i++) const CensorItemLoadingWidgets(),
unit: '°C', ],
icon: BootstrapIcons.thermometer_half, );
textColor: Colors.white, case ResultState.hasData:
color: AppColor.secondary, return GridView(
iconColor: Colors.white, padding: EdgeInsets.all(16.r),
censorIdentifier: censorIdentifier, shrinkWrap: true,
onTap: () async { gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
await Navigator.push( crossAxisCount: 2,
context, crossAxisSpacing: 16.r,
MaterialPageRoute( mainAxisSpacing: 16.r,
builder: (context) => const TemperatureScreen())); childAspectRatio: 0.9,
}, ),
), children: [
DataDisplayerWidget( DataDisplayerWidget(
title: 'Soil Moisture', title: 'Temperature',
subtitle: 'kelembaban tanah', subtitle: 'Suhu tanah',
value: '40', value: '28',
unit: '%', unit: '°C',
icon: Icons.water_outlined, icon: BootstrapIcons.thermometer_half,
color: Colors.white, textColor: Colors.white,
censorIdentifier: censorIdentifier, color: AppColor.secondary,
onTap: () async { iconColor: Colors.white,
await Navigator.push( censorIdentifier: censorIdentifier,
context, onTap: () async {
MaterialPageRoute( await Navigator.push(
builder: (context) => const SoilMoistureScreen(), context,
MaterialPageRoute(
builder: (context) => const TemperatureScreen()));
},
), ),
); DataDisplayerWidget(
}, title: 'Soil Moisture',
), subtitle: 'kelembaban tanah',
DataDisplayerWidget( value: '40',
title: 'Acid Level (PH)', unit: '%',
subtitle: 'tingkat keasaman', icon: Icons.water_outlined,
value: '6.5', color: Colors.white,
unit: 'pH', censorIdentifier: censorIdentifier,
icon: BootstrapIcons.pie_chart, onTap: () async {
color: Colors.white, await Navigator.push(
censorIdentifier: censorIdentifier, context,
onTap: () {}, MaterialPageRoute(
), builder: (context) => const SoilMoistureScreen(),
DataDisplayerWidget( ),
title: 'Conductivity', );
subtitle: 'Daya Arus Listrik', },
value: '234', ),
unit: 'µS/cm', DataDisplayerWidget(
icon: Icons.electric_bolt, title: 'Acid Level (PH)',
color: Colors.white, subtitle: 'tingkat keasaman',
censorIdentifier: censorIdentifier, value: '6.5',
onTap: () async { unit: 'pH',
context.push(AppRoute.humidity, extra: '60'); icon: BootstrapIcons.pie_chart,
}, color: Colors.white,
), censorIdentifier: censorIdentifier,
DataDisplayerWidget( onTap: () {},
title: 'Nitrogen', ),
subtitle: 'Kadar Nitrogen', DataDisplayerWidget(
value: '30', title: 'Conductivity',
unit: 'ppm', subtitle: 'Daya Arus Listrik',
icon: CupertinoIcons.eyedropper, value: '234',
color: Colors.white, unit: 'µS/cm',
onTap: () {}, icon: Icons.electric_bolt,
), color: Colors.white,
DataDisplayerWidget( censorIdentifier: censorIdentifier,
title: 'Potassium', onTap: () async {
subtitle: 'Kadar kalium', context.push(AppRoute.humidity, extra: '60');
value: '20', },
unit: 'ppm', ),
icon: CupertinoIcons.eyedropper, DataDisplayerWidget(
color: Colors.white, title: 'Nitrogen',
onTap: () {}, subtitle: 'Kadar Nitrogen',
), value: '30',
DataDisplayerWidget( unit: 'ppm',
title: 'Phosphorus', icon: CupertinoIcons.eyedropper,
subtitle: 'Kadar Fosfor', color: Colors.white,
value: '54', onTap: () {},
unit: 'ppm', ),
icon: CupertinoIcons.eyedropper, DataDisplayerWidget(
color: Colors.white, title: 'Potassium',
onTap: () {}, 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();
}
});
} }
} }

View File

@ -1,10 +1,7 @@
import 'dart:io';
import 'package:agrilink_vocpro/core/constant/app_color.dart'; import 'package:agrilink_vocpro/core/constant/app_color.dart';
import 'package:agrilink_vocpro/core/constant/app_theme.dart'; import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:agrilink_vocpro/core/route/app_route.dart'; import 'package:agrilink_vocpro/core/route/app_route.dart';
import 'package:bootstrap_icons/bootstrap_icons.dart'; import 'package:bootstrap_icons/bootstrap_icons.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';