feat: add every censor detail screen

This commit is contained in:
Syaroful 2024-10-01 10:49:55 +07:00
parent 0ce3129da5
commit 9e9cc57e54
29 changed files with 1218 additions and 217 deletions

View File

@ -2,7 +2,8 @@
<application <application
android:label="agrilink_vocpro" android:label="agrilink_vocpro"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -1,47 +1,48 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class AppTheme { class AppTheme {
static TextStyle headline1 = const TextStyle( static TextStyle headline1 = TextStyle(
fontSize: 32, fontSize: 32.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
letterSpacing: 1, letterSpacing: 1,
color: Colors.black, color: Colors.black,
); );
static TextStyle titleLarge = const TextStyle( static TextStyle titleLarge = TextStyle(
fontSize: 17, fontSize: 17.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.black, color: Colors.black,
); );
static TextStyle titleMedium = TextStyle( static TextStyle titleMedium = TextStyle(
fontSize: 16, fontSize: 16.sp,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Colors.grey.shade600, color: Colors.grey.shade600,
); );
static TextStyle titleSmall = const TextStyle( static TextStyle titleSmall = TextStyle(
fontSize: 12, fontSize: 12.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.black, color: Colors.black,
); );
static TextStyle labelLarge = const TextStyle( static TextStyle labelLarge = TextStyle(
fontSize: 16, fontSize: 16.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.black, color: Colors.black,
); );
static TextStyle labelMedium = const TextStyle( static TextStyle labelMedium = TextStyle(
fontSize: 14, fontSize: 14.sp,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Colors.black, color: Colors.black,
); );
static TextStyle labelSmall = const TextStyle( static TextStyle labelSmall = TextStyle(
fontSize: 12, fontSize: 12.sp,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Colors.grey, color: Colors.grey,
); );
static TextStyle hintStyle = const TextStyle( static TextStyle hintStyle = TextStyle(
fontSize: 14, fontSize: 14.sp,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Colors.grey, color: Colors.grey,
); );

View File

@ -1,6 +1,7 @@
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/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/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,7 +16,7 @@ class AppRoute {
static const String humidity = '/dashboard/humidity'; static const String humidity = '/dashboard/humidity';
static const String temperature = '/temperature'; static const String temperature = '/temperature';
static const String soil = '/soil'; static const String soil = '/soil';
static const String light = '/light'; static const String light = '/dashboard/light';
static const String water = '/water'; static const String water = '/water';
static const String acidity = '/acidity'; static const String acidity = '/acidity';
@ -45,6 +46,14 @@ class AppRoute {
path: 'humidity', path: 'humidity',
builder: (context, state) => const HumidityScreen(), 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);
},
)
], ],
), ),
], ],

View File

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
class ControlProvider extends ChangeNotifier {
// control 1
bool _control_1 = false;
bool get control_1 => _control_1;
switchControl1() {
_control_1 = !_control_1;
notifyListeners();
}
// control 2
bool _control_2 = false;
bool get control_2 => _control_2;
switchControl2() {
_control_2 = !_control_2;
notifyListeners();
}
// control 3
bool _control_3 = false;
bool get control_3 => _control_3;
switchControl3() {
_control_3 = !_control_3;
notifyListeners();
}
// control 4
bool _control_4 = false;
bool get control_4 => _control_4;
switchControl4() {
_control_4 = !_control_4;
notifyListeners();
}
// control 5
bool _control_5 = false;
bool get control_5 => _control_5;
switchControl5() {
_control_5 = !_control_5;
notifyListeners();
}
// control 6
bool _control_6 = false;
bool get control_6 => _control_6;
switchControl6() {
_control_6 = !_control_6;
notifyListeners();
}
}

View File

@ -0,0 +1,87 @@
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:agrilink_vocpro/features/control/provider/control_provider.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ControlScreen extends StatelessWidget {
const ControlScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Control', style: AppTheme.labelMedium),
centerTitle: true,
backgroundColor: Colors.white,
scrolledUnderElevation: 0,
),
body: Consumer<ControlProvider>(builder: (context, provider, child) {
return SafeArea(
child: ListView(
children: [
ListTile(
title: const Text('Control 1'),
subtitle: const Text('Control 1 description'),
trailing: Switch(
value: provider.control_1,
onChanged: (value) {
provider.switchControl1();
},
),
),
ListTile(
title: const Text('Control 2'),
subtitle: const Text('Control 2 description'),
trailing: Switch(
value: provider.control_2,
onChanged: (value) {
provider.switchControl2();
},
),
),
ListTile(
title: const Text('Control 3'),
subtitle: const Text('Control 3 description'),
trailing: Switch(
value: provider.control_3,
onChanged: (value) {
provider.switchControl3();
},
),
),
ListTile(
title: const Text('Control 4'),
subtitle: const Text('Control 4 description'),
trailing: Switch(
value: provider.control_4,
onChanged: (value) {
provider.switchControl4();
},
),
),
ListTile(
title: const Text('Control 5'),
subtitle: const Text('Control 5 description'),
trailing: Switch(
value: provider.control_5,
onChanged: (value) {
provider.switchControl5();
},
),
),
ListTile(
title: const Text('Control 6'),
subtitle: const Text('Control 6 description'),
trailing: Switch(
value: provider.control_6,
onChanged: (value) {
provider.switchControl6();
},
),
),
],
));
}),
);
}
}

View File

@ -0,0 +1,19 @@
import 'dart:ui';
class CensorDataRule {
int minPercentage;
int maxPercentage;
String censorText;
String description;
String action;
Color? color;
CensorDataRule({
required this.minPercentage,
required this.maxPercentage,
required this.censorText,
required this.description,
required this.action,
this.color,
});
}

View File

@ -1,4 +1,6 @@
import 'package:agrilink_vocpro/features/control/view/control_screen.dart';
import 'package:agrilink_vocpro/features/home/view/home_screen.dart'; import 'package:agrilink_vocpro/features/home/view/home_screen.dart';
import 'package:agrilink_vocpro/features/plants/view/plants_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class DashboardProvider extends ChangeNotifier { class DashboardProvider extends ChangeNotifier {
@ -14,8 +16,8 @@ class DashboardProvider extends ChangeNotifier {
final List<Widget> _screens = [ final List<Widget> _screens = [
const HomeScreen(), const HomeScreen(),
const Center(child: Text('Control')), const ControlScreen(),
const Center(child: Text('Plants')), const PlantsScreen(),
const Center(child: Text('Settings')), const Center(child: Text('Settings')),
]; ];

View File

@ -1,8 +1,11 @@
import 'package:agrilink_vocpro/core/constant/app_theme.dart'; import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:agrilink_vocpro/features/home/pages/humidity/widgets/circle_chart.dart'; import 'package:agrilink_vocpro/features/home/pages/humidity/widgets/circle_chart.dart';
import 'package:agrilink_vocpro/features/home/provider/home_provider.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:provider/provider.dart';
class HumidityScreen extends StatelessWidget { class HumidityScreen extends StatelessWidget {
const HumidityScreen({super.key}); const HumidityScreen({super.key});
@ -13,6 +16,7 @@ class HumidityScreen extends StatelessWidget {
appBar: AppBar( appBar: AppBar(
title: Text('Humidity', style: AppTheme.labelLarge), title: Text('Humidity', style: AppTheme.labelLarge),
centerTitle: true, centerTitle: true,
scrolledUnderElevation: 0,
leading: IconButton( leading: IconButton(
icon: const Icon(CupertinoIcons.back), icon: const Icon(CupertinoIcons.back),
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
@ -29,22 +33,76 @@ class HumidityScreen extends StatelessWidget {
], ],
), ),
body: SafeArea( body: SafeArea(
child: ListView( child: Consumer<HomeProvider>(builder: (context, provider, child) {
children: [ return ListView(
SizedBox( children: [
height: MediaQuery.of(context).size.height * 0.05, SizedBox(
), height: MediaQuery.of(context).size.height * 0.05,
const SizedBox(
height: 320,
width: double.infinity,
child: CircleChart(
percentage: 60.5,
icon: BootstrapIcons.droplet_half,
), ),
), const SizedBox(
const SizedBox(height: 16), height: 320,
], width: double.infinity,
), child: CircleChart(
percentage: 60.5,
icon: BootstrapIcons.droplet_half,
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Humidity',
style: AppTheme.labelMedium,
textAlign: TextAlign.center,
),
IconButton(
iconSize: 20.r,
color: Colors.blue,
onPressed: () {},
icon: const Icon(BootstrapIcons.info_circle))
],
),
const SizedBox(height: 16),
Padding(
padding: EdgeInsets.only(left: 16.w),
child: const Text('Deskripsi'),
),
const SizedBox(height: 16),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: provider.humidtyRules.length,
itemBuilder: (context, index) {
final item = provider.humidtyRules[index];
return Theme(
data: Theme.of(context)
.copyWith(dividerColor: Colors.transparent),
child: ExpansionTile(
trailing: Text(
item.censorText,
style: TextStyle(color: item.color),
),
expandedCrossAxisAlignment: CrossAxisAlignment.start,
childrenPadding: EdgeInsets.all(16.r),
title: Text(
'Kelembaban ${item.minPercentage}% - ${item.maxPercentage}%'),
children: [
Text(
item.description,
style: AppTheme.hintStyle,
),
SizedBox(height: 8.h),
Text('Tindakan', style: AppTheme.labelMedium),
SizedBox(height: 8.h),
Text(item.action),
],
),
);
})
],
);
}),
), ),
); );
} }

View File

@ -6,10 +6,14 @@ class CircleChart extends StatefulWidget {
super.key, super.key,
required this.percentage, required this.percentage,
required this.icon, required this.icon,
this.colorStart,
this.colorEnd,
}); });
final double percentage; final double percentage;
final IconData icon; final IconData icon;
final Color? colorStart;
final Color? colorEnd;
@override @override
State<CircleChart> createState() => _CircleChartState(); State<CircleChart> createState() => _CircleChartState();
@ -108,6 +112,9 @@ class _CircleChartState extends State<CircleChart> {
Color _getAnimatedColor(double percentage) { Color _getAnimatedColor(double percentage) {
return Color.lerp( return Color.lerp(
Colors.green, Colors.blue, percentage / widget.percentage)!; widget.colorStart ?? Colors.green,
widget.colorEnd ?? Colors.blue,
percentage / widget.percentage,
)!;
} }
} }

View File

@ -0,0 +1,207 @@
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';
import 'package:gauge_indicator/gauge_indicator.dart';
class LightScreen extends StatelessWidget {
const LightScreen({super.key, this.lightIntensity = 0});
final double lightIntensity;
double get value => lightIntensity;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Light', style: AppTheme.titleLarge),
centerTitle: true,
backgroundColor: Colors.white,
scrolledUnderElevation: 0,
actions: [
Padding(
padding: const EdgeInsets.only(right: 16),
child: Icon(
BootstrapIcons.sun,
color: Colors.yellow.shade600,
),
)
],
),
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: [
const Icon(BootstrapIcons.sun,
size: 32, color: Colors.orange),
Text(
'${value.toStringAsFixed(0)} lux', // Animated percentage text
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
],
),
),
AnimatedRadialGauge(
duration: const Duration(seconds: 3),
curve: Curves.easeOut,
value: value,
axis: GaugeAxis(
degrees: 360,
min: 0,
max: 5000,
style: GaugeAxisStyle(
background: Colors.grey.shade100,
thickness: 50,
),
progressBar: GaugeBasicProgressBar(
gradient: GaugeAxisGradient(colors: [
Colors.yellow.shade100,
Colors.orange.shade200,
]),
),
),
),
],
),
),
const SizedBox(height: 16),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Intensitas Cahaya',
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('Deskripsi'),
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,
// ),
// ],
// ),
// ),
// ],
// )
],
),
),
);
}
}

View File

@ -39,6 +39,8 @@ class SoilMoistureScreen extends StatelessWidget {
child: CircleChart( child: CircleChart(
percentage: 60.5, percentage: 60.5,
icon: Icons.water_outlined, icon: Icons.water_outlined,
colorStart: Colors.lime,
colorEnd: Colors.brown,
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),

View File

@ -1,10 +1,14 @@
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:bootstrap_icons/bootstrap_icons.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:gauge_indicator/gauge_indicator.dart';
class TemperatureScreen extends StatelessWidget { class TemperatureScreen extends StatelessWidget {
const TemperatureScreen({super.key}); const TemperatureScreen({super.key});
double get value => 29;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -12,6 +16,7 @@ class TemperatureScreen extends StatelessWidget {
title: Text('Temperature', style: AppTheme.titleLarge), title: Text('Temperature', style: AppTheme.titleLarge),
centerTitle: true, centerTitle: true,
backgroundColor: Colors.white, backgroundColor: Colors.white,
scrolledUnderElevation: 0,
actions: const [ actions: const [
Padding( Padding(
padding: EdgeInsets.only(right: 16), padding: EdgeInsets.only(right: 16),
@ -24,22 +29,177 @@ class TemperatureScreen extends StatelessWidget {
), ),
body: SafeArea( body: SafeArea(
child: ListView( child: ListView(
padding: EdgeInsets.all(16.w),
children: [ children: [
SizedBox( SizedBox(
height: MediaQuery.of(context).size.height * 0.05, height: MediaQuery.of(context).size.height * 0.05,
), ),
Center( SizedBox(
child: SizedBox( height: 240.h,
height: 320, child: Stack(
width: 320, fit: StackFit.expand,
child: CircularProgressIndicator( children: [
strokeWidth: 10, Center(
backgroundColor: Colors.grey.shade200, child: Column(
value: 0.5, mainAxisSize: MainAxisSize.min,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.red), children: [
SizedBox(
height: 80.h,
),
const Icon(BootstrapIcons.thermometer_half,
size: 32, color: Colors.orange),
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),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Temperature',
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('Deskripsi'),
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,
),
],
),
),
],
)
], ],
), ),
), ),

View File

@ -1,5 +1,59 @@
import 'package:agrilink_vocpro/features/dashboard/model/censor_data_rule.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class HomeProvider extends ChangeNotifier { class HomeProvider extends ChangeNotifier {
final DateTime currentDate = DateTime.now(); final DateTime currentDate = DateTime.now();
List<CensorDataRule> humidtyRules = [
CensorDataRule(
minPercentage: 0,
maxPercentage: 30,
censorText: 'Very Low',
description:
'Udara sangat kering. Tanaman bisa mengalami stress akibat kekurangan air.',
action:
'Aktifkan sistem penyiraman atau humidifier untuk menaikkan kelembaban. Periksa juga apakah ada kebocoran pada sistem irigasi yang mengakibatkan kelembaban terlalu rendah.',
color: Colors.red,
),
CensorDataRule(
minPercentage: 31,
maxPercentage: 50,
censorText: 'Low',
description:
'Kelembaban masih cukup rendah. Beberapa jenis tanaman mungkin sudah mulai terpengaruh.',
action:
'Pertimbangkan untuk menambah irigasi atau memperpanjang durasi penyiraman. Pantau tanaman secara berkala.',
color: Colors.orange,
),
CensorDataRule(
minPercentage: 51,
maxPercentage: 70,
censorText: 'Normal',
description:
'Ini adalah kelembaban yang ideal untuk sebagian besar tanaman dalam greenhouse.',
action:
'Pertahankan kondisi ini. Tidak ada tindakan yang diperlukan kecuali jika ada perubahan mendadak.',
color: Colors.green,
),
CensorDataRule(
minPercentage: 71,
maxPercentage: 85,
censorText: 'High',
description:
'Udara mulai terlalu lembap. Kelembaban tinggi dapat meningkatkan risiko penyakit jamur atau bakteri.',
action:
'Aktifkan ventilasi atau kipas untuk mengurangi kelembaban. Pastikan aliran udara di greenhouse cukup baik.',
color: Colors.lime,
),
CensorDataRule(
minPercentage: 86,
maxPercentage: 100,
censorText: 'Very High',
description:
'Udara sangat lembap, yang bisa berisiko menyebabkan jamur, lumut, dan penyakit tanaman.',
action:
'Segera aktifkan sistem ventilasi maksimal, mungkin juga gunakan dehumidifier jika diperlukan. Kurangi frekuensi penyiraman atau periksa sistem irigasi agar tidak berlebihan.',
color: Colors.brown,
),
];
} }

View File

@ -1,61 +1,66 @@
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/extension/extention.dart'; import 'package:agrilink_vocpro/core/extension/extention.dart';
import 'package:agrilink_vocpro/core/route/app_route.dart'; import 'package:agrilink_vocpro/features/home/widgets/list_data_from_censor_npk1.dart';
import 'package:agrilink_vocpro/features/home/pages/soil_moisture/view/soil_moisture_screen.dart'; import 'package:agrilink_vocpro/features/home/widgets/list_data_from_censor_npk2.dart';
import 'package:agrilink_vocpro/features/home/pages/temperature/view/temperature_screen.dart'; import 'package:agrilink_vocpro/features/home/widgets/list_data_from_main_censor.dart';
import 'package:agrilink_vocpro/features/home/provider/home_provider.dart'; import 'package:animated_segmented_tab_control/animated_segmented_tab_control.dart';
import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart';
import 'package:agrilink_vocpro/features/home/pages/humidity/view/humidity_screen.dart';
import 'package:bootstrap_icons/bootstrap_icons.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
class HomeScreen extends StatelessWidget { class HomeScreen extends StatefulWidget {
const HomeScreen({super.key}); const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return SafeArea(
body: SafeArea( child: Scaffold(
child: RefreshIndicator( appBar: AppBar(
onRefresh: () async { toolbarHeight: 200.h,
await Future.delayed(const Duration(seconds: 1)); elevation: 0,
}, backgroundColor: Colors.white,
child: ListView( scrolledUnderElevation: 0,
padding: const EdgeInsets.all(16), flexibleSpace: Padding(
children: [ padding: EdgeInsets.symmetric(horizontal: 12.w),
Row( child: Column(
children: [ children: [
const CircleAvatar( Row(
radius: 24, children: [
backgroundColor: AppColor.primary, CircleAvatar(
child: Icon( radius: 24.r,
Icons.person, backgroundColor: AppColor.primary,
color: Colors.white, child: Icon(
size: 24, Icons.person,
color: Colors.white,
size: 24.r,
),
), ),
), SizedBox(width: 16.w),
const SizedBox(width: 16), Column(
Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Text( Text(
getGreeting(DateTime.now().toString()), getGreeting(DateTime.now().toString()),
style: AppTheme.titleMedium, style: AppTheme.labelSmall,
), ),
Text( Text(
'Fikril Mahesaputra', 'Fikril Mahesaputra',
style: AppTheme.titleLarge, style: AppTheme.labelMedium,
), ),
], ],
), ),
], ],
), ),
const SizedBox(height: 24), SizedBox(
Consumer<HomeProvider>(builder: (context, provider, child) { height: 8.h,
return Container( ),
Container(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
height: MediaQuery.of(context).size.height * 0.17, height: MediaQuery.of(context).size.height * 0.17,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -99,84 +104,47 @@ class HomeScreen extends StatelessWidget {
), ),
], ],
), ),
);
}),
const SizedBox(height: 16),
Text('Linked Device', style: AppTheme.titleMedium),
const SizedBox(height: 16),
GridView(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
), ),
children: [ ],
DataDisplayerWidget( ),
title: 'Humidity',
subtitle: 'kelembaban udara',
value: '60',
unit: '%',
icon: BootstrapIcons.droplet_half,
textColor: Colors.white,
color: AppColor.secondary,
iconColor: Colors.white,
onTap: () async {
context.push(AppRoute.humidity, extra: '60');
},
),
DataDisplayerWidget(
title: 'Temperature',
subtitle: 'suhu greenhouse',
value: '28',
unit: '°C',
icon: BootstrapIcons.thermometer_half,
color: Colors.white,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const TemperatureScreen()));
},
),
const DataDisplayerWidget(
title: 'Light',
subtitle: 'intensitas cahaya',
value: '1000',
unit: 'lux',
icon: BootstrapIcons.sun,
color: Colors.white,
),
DataDisplayerWidget(
title: 'Soil Moisture',
subtitle: 'kelembaban tanah',
value: '40',
unit: '%',
icon: Icons.water_outlined,
color: Colors.white,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SoilMoistureScreen(),
),
);
},
),
const DataDisplayerWidget(
title: 'Acid Level',
subtitle: 'tingkat keasaman',
value: '6.5',
unit: '',
icon: BootstrapIcons.pie_chart,
color: Colors.white,
)
],
)
],
), ),
), ),
body: DefaultTabController(
length: 3,
child: Stack(
children: [
Padding(
padding:
EdgeInsets.symmetric(horizontal: 64.w, vertical: 16.h),
child: SegmentedTabControl(
height: 32.h,
tabTextColor: Colors.black,
tabPadding: EdgeInsets.zero,
barDecoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24.r),
),
indicatorDecoration: BoxDecoration(
color: AppColor.primary,
borderRadius: BorderRadius.circular(24.r),
),
textStyle: AppTheme.labelSmall,
tabs: const [
SegmentTab(label: 'Main Censor'),
SegmentTab(label: 'NPK 1'),
SegmentTab(label: 'NPK 2'),
]),
),
Padding(
padding: EdgeInsets.only(top: 64.h),
child: const TabBarView(children: [
ListDataFromMainCensor(),
ListDataFromCensorNpk1(),
ListDataFromCensorNpk2(),
]),
)
],
)),
), ),
); );
} }

View File

@ -1,5 +1,6 @@
import 'package:agrilink_vocpro/core/constant/app_theme.dart'; import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class DataDisplayerWidget extends StatelessWidget { class DataDisplayerWidget extends StatelessWidget {
const DataDisplayerWidget({ const DataDisplayerWidget({
@ -12,6 +13,7 @@ class DataDisplayerWidget extends StatelessWidget {
this.iconColor = Colors.teal, this.iconColor = Colors.teal,
this.textColor = Colors.black, this.textColor = Colors.black,
required this.unit, required this.unit,
this.censorIdentifier,
this.onTap, this.onTap,
}); });
@ -23,6 +25,7 @@ class DataDisplayerWidget extends StatelessWidget {
final Color iconColor; final Color iconColor;
final Color textColor; final Color textColor;
final String unit; final String unit;
final String? censorIdentifier;
final VoidCallback? onTap; final VoidCallback? onTap;
@override @override
@ -33,49 +36,54 @@ class DataDisplayerWidget extends StatelessWidget {
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: color, backgroundColor: color,
padding: const EdgeInsets.all(12), // Padding di dalam button padding: EdgeInsets.all(12.r), // Padding di dalam button
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16), // Bentuk sudut yang bundar borderRadius: BorderRadius.circular(16.r), // Bentuk sudut yang bundar
), ),
elevation: 20, // Efek bayangan elevation: 20, // Efek bayangan
shadowColor: Colors.grey.withOpacity(0.2), shadowColor: Colors.grey.withOpacity(0.2),
), ),
child: SizedBox( child: Column(
height: crossAxisAlignment: CrossAxisAlignment.start,
MediaQuery.of(context).size.height * 0.2, // Mengatur tinggi button // Tidak perlu menggunakan mainAxisSize: MainAxisSize.min di sini
child: Column( children: [
crossAxisAlignment: CrossAxisAlignment.start, Align(
children: [ alignment: Alignment.centerRight,
Icon(icon, color: iconColor, size: 32), child: Text(
const SizedBox(height: 8), censorIdentifier ?? '',
Column( style: AppTheme.labelSmall
crossAxisAlignment: CrossAxisAlignment.start, .copyWith(color: textColor.withOpacity(0.5)),
children: [
Text(
title,
style: AppTheme.labelMedium.copyWith(color: textColor),
),
Text(
subtitle,
style: AppTheme.labelSmall
.copyWith(color: textColor.withOpacity(0.5)),
),
],
), ),
const Spacer(), ),
Row( Icon(icon, color: iconColor, size: 32.r),
children: [ SizedBox(height: 8.h),
Text( Column(
value, crossAxisAlignment: CrossAxisAlignment.start,
style: AppTheme.headline1.copyWith(color: textColor), children: [
), Text(
const SizedBox(width: 4), title,
Text(unit, style: AppTheme.labelMedium.copyWith(color: textColor),
style: AppTheme.titleMedium.copyWith(color: textColor)), ),
], Text(
), subtitle,
], style: AppTheme.labelSmall
), .copyWith(color: textColor.withOpacity(0.5)),
),
],
),
const Spacer(),
Row(
children: [
Text(
value,
style: AppTheme.headline1.copyWith(color: textColor),
),
SizedBox(width: 4.w),
Text(unit,
style: AppTheme.titleMedium.copyWith(color: textColor)),
],
),
],
), ),
); );
} }

View File

@ -0,0 +1,116 @@
import 'package:agrilink_vocpro/core/constant/app_color.dart';
import 'package:agrilink_vocpro/core/route/app_route.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/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';
class ListDataFromCensorNpk1 extends StatelessWidget {
const ListDataFromCensorNpk1({
super.key,
});
@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(),
),
);
},
),
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: () {},
),
],
);
}
}

View File

@ -0,0 +1,116 @@
import 'package:agrilink_vocpro/core/constant/app_color.dart';
import 'package:agrilink_vocpro/core/route/app_route.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/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';
class ListDataFromCensorNpk2 extends StatelessWidget {
const ListDataFromCensorNpk2({
super.key,
});
@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(),
),
);
},
),
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: () {},
),
],
);
}
}

View File

@ -0,0 +1,70 @@
import 'package:agrilink_vocpro/core/constant/app_color.dart';
import 'package:agrilink_vocpro/core/route/app_route.dart';
import 'package:agrilink_vocpro/features/home/pages/temperature/view/temperature_screen.dart';
import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart';
import 'package:bootstrap_icons/bootstrap_icons.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:go_router/go_router.dart';
class ListDataFromMainCensor extends StatelessWidget {
const ListDataFromMainCensor({
super.key,
});
@override
Widget build(BuildContext context) {
return GridView(
padding: EdgeInsets.all(16.r),
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16.r,
mainAxisSpacing: 16.r,
childAspectRatio: 0.9,
),
children: [
DataDisplayerWidget(
title: 'Humidity',
subtitle: 'kelembaban udara',
value: '60',
unit: '%',
icon: BootstrapIcons.droplet_half,
textColor: Colors.white,
color: AppColor.secondary,
iconColor: Colors.white,
censorIdentifier: 'NPK 1',
onTap: () async {
context.push(AppRoute.humidity, extra: '60');
},
),
DataDisplayerWidget(
title: 'Temperature',
subtitle: 'suhu greenhouse',
value: '28',
unit: '°C',
icon: BootstrapIcons.thermometer_half,
color: Colors.white,
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const TemperatureScreen()));
},
),
DataDisplayerWidget(
title: 'Light',
subtitle: 'intensitas cahaya',
value: '1000',
unit: 'lux',
icon: BootstrapIcons.sun,
color: Colors.white,
onTap: () async {
context.push('${AppRoute.light}/300');
},
),
],
);
}
}

View File

@ -0,0 +1,16 @@
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
import 'package:flutter/material.dart';
class PlantsScreen extends StatelessWidget {
const PlantsScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Text('Coming Soon', style: AppTheme.labelMedium),
)),
);
}
}

View File

@ -1,12 +1,20 @@
import 'package:agrilink_vocpro/core/route/app_route.dart'; import 'package:agrilink_vocpro/core/route/app_route.dart';
import 'package:agrilink_vocpro/features/auth/provider/auth_provider.dart'; import 'package:agrilink_vocpro/features/auth/provider/auth_provider.dart';
import 'package:agrilink_vocpro/features/control/provider/control_provider.dart';
import 'package:agrilink_vocpro/features/dashboard/provider/dashboard_provider.dart'; import 'package:agrilink_vocpro/features/dashboard/provider/dashboard_provider.dart';
import 'package:agrilink_vocpro/features/home/provider/home_provider.dart'; import 'package:agrilink_vocpro/features/home/provider/home_provider.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
void main() { void main() {
runApp(const MyApp()); WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp, // Locks the app in portrait mode
]).then((_) {
runApp(const MyApp());
});
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
@ -20,17 +28,23 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (context) => AuthProvider()), ChangeNotifierProvider(create: (context) => AuthProvider()),
ChangeNotifierProvider(create: (context) => HomeProvider()), ChangeNotifierProvider(create: (context) => HomeProvider()),
ChangeNotifierProvider(create: (context) => DashboardProvider()), ChangeNotifierProvider(create: (context) => DashboardProvider()),
ChangeNotifierProvider(create: (context) => ControlProvider()),
], ],
child: MaterialApp.router( child: ScreenUtilInit(
debugShowCheckedModeBanner: false, designSize: const Size(360, 800),
title: 'Flutter Demo', minTextAdapt: true,
theme: ThemeData( builder: (_, context) {
scaffoldBackgroundColor: Colors.white, return MaterialApp.router(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal), debugShowCheckedModeBanner: false,
useMaterial3: true, title: 'Flutter Demo',
), theme: ThemeData(
routerConfig: AppRoute.router, scaffoldBackgroundColor: Colors.white,
), colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
useMaterial3: true,
),
routerConfig: AppRoute.router,
);
}),
); );
} }
} }

View File

@ -1,6 +1,14 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
animated_segmented_tab_control:
dependency: "direct main"
description:
name: animated_segmented_tab_control
sha256: "4c04f5510037b1c30dbed00efae77559cc4e11f0fe2207c2358252d1870e4ab1"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -134,6 +142,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "4.0.0"
flutter_screenutil:
dependency: "direct main"
description:
name: flutter_screenutil
sha256: "8239210dd68bee6b0577aa4a090890342d04a136ce1c81f98ee513fc0ce891de"
url: "https://pub.dev"
source: hosted
version: "5.9.3"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -144,6 +160,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
gauge_indicator:
dependency: "direct main"
description:
name: gauge_indicator
sha256: "483abfae360ddffdf7b89fbd25192f83d1a6513d5da18f2388131566ab0793fd"
url: "https://pub.dev"
source: hosted
version: "0.4.3"
go_router: go_router:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -42,6 +42,9 @@ dependencies:
bootstrap_icons: ^1.11.3 bootstrap_icons: ^1.11.3
fl_chart: ^0.69.0 fl_chart: ^0.69.0
google_fonts: ^6.2.1 google_fonts: ^6.2.1
animated_segmented_tab_control: ^2.0.0
flutter_screenutil: ^5.9.3
gauge_indicator: ^0.4.3
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: