feat: add basic route, splash, and login screen
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 23 KiB |
BIN
agrilink_vocpro/assets/images/app_logo.png
Normal file
|
After Width: | Height: | Size: 362 KiB |
|
|
@ -11,4 +11,5 @@ class AppColor {
|
|||
static const Color greenTextDark = Color(0xFF00913A);
|
||||
|
||||
static const Color textDisable = Color(0xFFBDBDBD);
|
||||
static const Color textDark = Color(0xFF4B4B51);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,16 @@ class AppTheme {
|
|||
letterSpacing: 1,
|
||||
color: Colors.black,
|
||||
);
|
||||
|
||||
static TextStyle titleLarge = const TextStyle(
|
||||
fontSize: 16,
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black,
|
||||
);
|
||||
static TextStyle titleMedium = const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black,
|
||||
static TextStyle titleMedium = TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.grey.shade600,
|
||||
);
|
||||
static TextStyle titleSmall = const TextStyle(
|
||||
fontSize: 12,
|
||||
|
|
@ -23,13 +24,24 @@ class AppTheme {
|
|||
color: Colors.black,
|
||||
);
|
||||
|
||||
static TextStyle labelLarge = const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black,
|
||||
);
|
||||
static TextStyle labelMedium = const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.black,
|
||||
);
|
||||
static TextStyle labelSmall = const TextStyle(
|
||||
fontSize: 10,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.grey,
|
||||
);
|
||||
|
||||
static TextStyle hintStyle = const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.grey,
|
||||
);
|
||||
|
|
|
|||
57
agrilink_vocpro/lib/core/route/app_route.dart
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import 'package:agrilink_vocpro/features/auth/view/login_screen.dart';
|
||||
import 'package:agrilink_vocpro/features/dashboard/view/dashboard_screen.dart';
|
||||
import 'package:agrilink_vocpro/features/home/pages/humidity/view/humidity_screen.dart';
|
||||
import 'package:agrilink_vocpro/features/splash/view/splash_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class AppRoute {
|
||||
static const String root = '/';
|
||||
static const String login = '/login';
|
||||
static const String dashboard = '/dashboard';
|
||||
static const String home = '/home';
|
||||
static const String profile = '/profile';
|
||||
static const String setting = '/setting';
|
||||
static const String humidity = '/dashboard/humidity';
|
||||
static const String temperature = '/temperature';
|
||||
static const String soil = '/soil';
|
||||
static const String light = '/light';
|
||||
static const String water = '/water';
|
||||
static const String acidity = '/acidity';
|
||||
|
||||
static final GoRouter router = GoRouter(
|
||||
initialLocation: root,
|
||||
routes: [
|
||||
//splash
|
||||
GoRoute(
|
||||
path: root,
|
||||
builder: (context, state) => const SplashScreen(),
|
||||
),
|
||||
//login
|
||||
GoRoute(
|
||||
path: login,
|
||||
builder: (context, state) => const LoginScreen(),
|
||||
),
|
||||
//dashboard
|
||||
GoRoute(
|
||||
path: dashboard,
|
||||
builder: (context, state) => const DashboardScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: dashboard,
|
||||
builder: (context, state) => const DashboardScreen(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: 'humidity',
|
||||
builder: (context, state) => const HumidityScreen(),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
errorBuilder: (context, state) => Scaffold(
|
||||
body: Center(
|
||||
child: Text('Error: ${state.error}'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
enum ResultState {
|
||||
initial,
|
||||
loading,
|
||||
noData,
|
||||
hasData,
|
||||
noData,
|
||||
error,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:agrilink_vocpro/core/constant/app_color.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
|
||||
class AppButton extends StatelessWidget {
|
||||
const AppButton({
|
||||
|
|
@ -24,14 +23,14 @@ class AppButton extends StatelessWidget {
|
|||
onPressed: onPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
shadowColor: Colors.transparent,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 14.sp, fontWeight: FontWeight.w500, fontFamily: 'Onest'),
|
||||
textStyle: const TextStyle(
|
||||
fontSize: 14, fontWeight: FontWeight.w500, fontFamily: 'Urbanist'),
|
||||
backgroundColor: backgroundColor,
|
||||
foregroundColor: foregroundColor,
|
||||
minimumSize: Size(double.infinity, 48.h),
|
||||
minimumSize: const Size(double.infinity, 48),
|
||||
shape: RoundedRectangleBorder(
|
||||
side: borderSide ?? BorderSide.none,
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
child: Text(text),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import 'package:agrilink_vocpro/core/constant/app_color.dart';
|
||||
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
|
||||
class CustomTextField extends StatelessWidget {
|
||||
const CustomTextField({
|
||||
class AppTextfield extends StatelessWidget {
|
||||
const AppTextfield({
|
||||
super.key,
|
||||
required this.controller,
|
||||
this.hintText = 'Enter Here',
|
||||
|
|
@ -20,16 +20,16 @@ class CustomTextField extends StatelessWidget {
|
|||
controller: controller,
|
||||
decoration: InputDecoration(
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: AppColor.textDisable, width: 1.r),
|
||||
borderRadius: BorderRadius.circular(8.r),
|
||||
gapPadding: 10.r),
|
||||
borderSide: const BorderSide(color: AppColor.textDisable, width: 1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: AppColor.primary, width: 1.r),
|
||||
borderRadius: BorderRadius.circular(8.r),
|
||||
gapPadding: 10.r),
|
||||
borderSide: const BorderSide(color: AppColor.primary, width: 1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
hintText: hintText,
|
||||
// hintStyle: AppTheme.hintStyle,
|
||||
suffixIcon: suffixIcon),
|
||||
hintStyle: AppTheme.hintStyle,
|
||||
suffixIcon: (suffixIcon != null) ? suffixIcon : null),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class AuthProvider extends ChangeNotifier {
|
||||
TextEditingController emailController = TextEditingController();
|
||||
TextEditingController passwordController = TextEditingController();
|
||||
|
||||
void controllerClear() {
|
||||
emailController.clear();
|
||||
passwordController.clear();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
import 'package:agrilink_vocpro/core/constant/app_color.dart';
|
||||
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
|
||||
import 'package:agrilink_vocpro/core/route/app_route.dart';
|
||||
import 'package:agrilink_vocpro/core/widgets/app_button.dart';
|
||||
import 'package:agrilink_vocpro/core/widgets/app_textfield.dart';
|
||||
import 'package:agrilink_vocpro/features/auth/provider/auth_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class LoginScreen extends StatelessWidget {
|
||||
const LoginScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: GestureDetector(
|
||||
onTap: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
child: SafeArea(
|
||||
child: Consumer<AuthProvider>(builder: (context, authP, child) {
|
||||
return ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
const SizedBox(height: 40),
|
||||
Text(
|
||||
'Hello Wellcome back 👋',
|
||||
style: AppTheme.titleLarge,
|
||||
),
|
||||
Text(
|
||||
'Happy to have you back',
|
||||
style: AppTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 40),
|
||||
Text('Email address', style: AppTheme.labelLarge),
|
||||
const SizedBox(height: 4),
|
||||
AppTextfield(
|
||||
controller: authP.emailController,
|
||||
hintText: 'Masukkan username',
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Text('Password', style: AppTheme.labelLarge),
|
||||
const SizedBox(height: 4),
|
||||
AppTextfield(
|
||||
controller: authP.passwordController,
|
||||
hintText: 'Masukkan password',
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
print('Forgot password?');
|
||||
},
|
||||
child: Text(
|
||||
'Forgot password?',
|
||||
textAlign: TextAlign.end,
|
||||
style: AppTheme.labelMedium
|
||||
.copyWith(color: AppColor.secondary),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
AppButton(
|
||||
onPressed: () {
|
||||
GoRouter.of(context).go(AppRoute.dashboard);
|
||||
},
|
||||
text: 'Login'),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:agrilink_vocpro/core/constant/app_color.dart';
|
||||
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
|
||||
import 'package:agrilink_vocpro/features/humidity/widgets/circle_chart.dart';
|
||||
import 'package:agrilink_vocpro/features/home/pages/humidity/widgets/circle_chart.dart';
|
||||
import 'package:bootstrap_icons/bootstrap_icons.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HumidityScreen extends StatelessWidget {
|
||||
|
|
@ -11,8 +11,12 @@ class HumidityScreen extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Humidity', style: AppTheme.titleLarge),
|
||||
title: Text('Humidity', style: AppTheme.labelLarge),
|
||||
centerTitle: true,
|
||||
leading: IconButton(
|
||||
icon: const Icon(CupertinoIcons.back),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
backgroundColor: Colors.white,
|
||||
actions: const [
|
||||
Padding(
|
||||
|
|
@ -33,7 +37,10 @@ class HumidityScreen extends StatelessWidget {
|
|||
const SizedBox(
|
||||
height: 320,
|
||||
width: double.infinity,
|
||||
child: CircleChart(humidityPercentage: 60.5),
|
||||
child: CircleChart(
|
||||
percentage: 60.5,
|
||||
icon: BootstrapIcons.droplet_half,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
import 'package:bootstrap_icons/bootstrap_icons.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CircleChart extends StatefulWidget {
|
||||
const CircleChart({super.key, required this.humidityPercentage});
|
||||
const CircleChart({
|
||||
super.key,
|
||||
required this.percentage,
|
||||
required this.icon,
|
||||
});
|
||||
|
||||
final double humidityPercentage;
|
||||
final double percentage;
|
||||
final IconData icon;
|
||||
|
||||
@override
|
||||
State<CircleChart> createState() => _CircleChartState();
|
||||
|
|
@ -17,7 +21,7 @@ class _CircleChartState extends State<CircleChart> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
Future.delayed(Duration.zero, () async {
|
||||
for (double i = 0; i <= widget.humidityPercentage; i++) {
|
||||
for (double i = 0; i <= widget.percentage; i++) {
|
||||
await Future.delayed(const Duration(milliseconds: 25), () {
|
||||
setState(() {
|
||||
currentPercentage = i;
|
||||
|
|
@ -62,8 +66,7 @@ class _CircleChartState extends State<CircleChart> {
|
|||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(BootstrapIcons.droplet_fill,
|
||||
size: 32, color: _getAnimatedColor(value)),
|
||||
Icon(widget.icon, size: 32, color: _getAnimatedColor(value)),
|
||||
Text(
|
||||
'${value.toStringAsFixed(0)}%', // Animated percentage text
|
||||
style: const TextStyle(
|
||||
|
|
@ -81,11 +84,11 @@ class _CircleChartState extends State<CircleChart> {
|
|||
);
|
||||
}
|
||||
|
||||
List<PieChartSectionData> _createSections(double humidityPercentage) {
|
||||
List<PieChartSectionData> _createSections(double percentage) {
|
||||
return [
|
||||
PieChartSectionData(
|
||||
color: Colors.white,
|
||||
value: humidityPercentage,
|
||||
value: percentage,
|
||||
title: '',
|
||||
radius: 50, // Size of the pie slice
|
||||
titleStyle: const TextStyle(
|
||||
|
|
@ -96,7 +99,7 @@ class _CircleChartState extends State<CircleChart> {
|
|||
),
|
||||
PieChartSectionData(
|
||||
color: Colors.white24,
|
||||
value: 100 - humidityPercentage,
|
||||
value: 100 - percentage,
|
||||
title: '',
|
||||
radius: 50,
|
||||
),
|
||||
|
|
@ -105,6 +108,6 @@ class _CircleChartState extends State<CircleChart> {
|
|||
|
||||
Color _getAnimatedColor(double percentage) {
|
||||
return Color.lerp(
|
||||
Colors.green, Colors.blue, percentage / widget.humidityPercentage)!;
|
||||
Colors.green, Colors.blue, percentage / widget.percentage)!;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
|
||||
import 'package:agrilink_vocpro/features/home/pages/humidity/widgets/circle_chart.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SoilMoistureScreen extends StatelessWidget {
|
||||
const SoilMoistureScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Soil Moisture', style: AppTheme.labelMedium),
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.white,
|
||||
leading: IconButton(
|
||||
icon: const Icon(CupertinoIcons.back),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
actions: const [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 16),
|
||||
child: Icon(
|
||||
Icons.water_outlined,
|
||||
color: Colors.blue,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
child: ListView(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.05,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 320,
|
||||
width: double.infinity,
|
||||
child: CircleChart(
|
||||
percentage: 60.5,
|
||||
icon: Icons.water_outlined,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
|
||||
import 'package:bootstrap_icons/bootstrap_icons.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TemperatureScreen extends StatelessWidget {
|
||||
const TemperatureScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Temperature', style: AppTheme.titleLarge),
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.white,
|
||||
actions: const [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 16),
|
||||
child: Icon(
|
||||
BootstrapIcons.thermometer_half,
|
||||
color: Colors.red,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
child: ListView(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.05,
|
||||
),
|
||||
Center(
|
||||
child: SizedBox(
|
||||
height: 320,
|
||||
width: 320,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 10,
|
||||
backgroundColor: Colors.grey.shade200,
|
||||
value: 0.5,
|
||||
valueColor: const AlwaysStoppedAnimation<Color>(Colors.red),
|
||||
),
|
||||
)),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
import 'package:agrilink_vocpro/core/constant/app_color.dart';
|
||||
import 'package:agrilink_vocpro/core/constant/app_theme.dart';
|
||||
import 'package:agrilink_vocpro/core/extension/extention.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/provider/home_provider.dart';
|
||||
import 'package:agrilink_vocpro/features/home/widgets/data_display_widget.dart';
|
||||
import 'package:agrilink_vocpro/features/humidity/view/humidity_screen.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:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class HomeScreen extends StatelessWidget {
|
||||
|
|
@ -14,14 +18,6 @@ class HomeScreen extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
'Home',
|
||||
style: AppTheme.titleMedium,
|
||||
),
|
||||
centerTitle: true,
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
body: SafeArea(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
|
|
@ -30,11 +26,34 @@ class HomeScreen extends StatelessWidget {
|
|||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
Text(
|
||||
'${getGreeting(DateTime.now().toString())}, Fikril',
|
||||
style: AppTheme.titleLarge,
|
||||
Row(
|
||||
children: [
|
||||
const CircleAvatar(
|
||||
radius: 24,
|
||||
backgroundColor: AppColor.primary,
|
||||
child: Icon(
|
||||
Icons.person,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
getGreeting(DateTime.now().toString()),
|
||||
style: AppTheme.titleMedium,
|
||||
),
|
||||
Text(
|
||||
'Fikril Mahesaputra',
|
||||
style: AppTheme.titleLarge,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const SizedBox(height: 24),
|
||||
Consumer<HomeProvider>(builder: (context, provider, child) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
|
|
@ -83,7 +102,7 @@ class HomeScreen extends StatelessWidget {
|
|||
);
|
||||
}),
|
||||
const SizedBox(height: 16),
|
||||
Text('Recent Activity', style: AppTheme.titleMedium),
|
||||
Text('Linked Device', style: AppTheme.titleMedium),
|
||||
const SizedBox(height: 16),
|
||||
GridView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
|
|
@ -104,19 +123,22 @@ class HomeScreen extends StatelessWidget {
|
|||
color: AppColor.secondary,
|
||||
iconColor: Colors.white,
|
||||
onTap: () async {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const HumidityScreen()));
|
||||
context.push(AppRoute.humidity, extra: '60');
|
||||
},
|
||||
),
|
||||
const DataDisplayerWidget(
|
||||
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',
|
||||
|
|
@ -126,13 +148,29 @@ class HomeScreen extends StatelessWidget {
|
|||
icon: BootstrapIcons.sun,
|
||||
color: Colors.white,
|
||||
),
|
||||
const DataDisplayerWidget(
|
||||
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,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:agrilink_vocpro/core/route/app_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class SplashScreen extends StatefulWidget {
|
||||
const SplashScreen({super.key});
|
||||
|
|
@ -8,8 +12,64 @@ class SplashScreen extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _SplashScreenState extends State<SplashScreen> {
|
||||
bool isLoggedIn = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_initialize();
|
||||
}
|
||||
|
||||
Future<void> _initialize() async {
|
||||
// final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||||
// bool isLoggedIn = await _checkLoginStatus(authProvider);
|
||||
_navigateAfterSplash(isLoggedIn);
|
||||
}
|
||||
|
||||
// Future<bool> _checkLoginStatus(AuthProvider authProvider) async {
|
||||
// SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
|
||||
// if (prefs.getKeys().isEmpty) return false;
|
||||
|
||||
// if (prefs.getBool('isLoggedIn') == true) {
|
||||
// String? token = prefs.getString('token');
|
||||
// String? refreshToken = prefs.getString('refreshToken');
|
||||
|
||||
// if (token != null && !JwtDecoder.isExpired(token)) {
|
||||
// return true;
|
||||
// } else if (refreshToken != null && !JwtDecoder.isExpired(refreshToken)) {
|
||||
// final result = await authProvider.refreshToken();
|
||||
// return result == ResultState.hasData;
|
||||
// } else {
|
||||
// prefs.remove('token');
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return false;
|
||||
// }
|
||||
|
||||
void _navigateAfterSplash(bool isLoggedIn) {
|
||||
Timer(const Duration(seconds: 2), () {
|
||||
if (isLoggedIn == true) {
|
||||
context.go(AppRoute.dashboard);
|
||||
} else {
|
||||
context.go(AppRoute.login);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder();
|
||||
return Scaffold(
|
||||
body: SafeArea(
|
||||
child: Center(
|
||||
child: Image.asset(
|
||||
'assets/images/app_logo.png',
|
||||
width: 80,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:agrilink_vocpro/core/route/app_route.dart';
|
||||
import 'package:agrilink_vocpro/features/auth/provider/auth_provider.dart';
|
||||
import 'package:agrilink_vocpro/features/dashboard/provider/dashboard_provider.dart';
|
||||
import 'package:agrilink_vocpro/features/dashboard/view/dashboard_screen.dart';
|
||||
import 'package:agrilink_vocpro/features/home/provider/home_provider.dart';
|
||||
import 'package:agrilink_vocpro/features/home/view/home_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
|
|
@ -17,10 +17,11 @@ class MyApp extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (context) => AuthProvider()),
|
||||
ChangeNotifierProvider(create: (context) => HomeProvider()),
|
||||
ChangeNotifierProvider(create: (context) => DashboardProvider()),
|
||||
],
|
||||
child: MaterialApp(
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Flutter Demo',
|
||||
theme: ThemeData(
|
||||
|
|
@ -28,7 +29,7 @@ class MyApp extends StatelessWidget {
|
|||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const DashboardScreen(),
|
||||
routerConfig: AppRoute.router,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@
|
|||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
@ -126,14 +134,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
|
@ -152,6 +152,22 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.7"
|
||||
google_fonts:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: google_fonts
|
||||
sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.2.1"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -248,6 +264,30 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.10"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -39,9 +39,9 @@ dependencies:
|
|||
intl: ^0.19.0
|
||||
dio: ^5.7.0
|
||||
go_router: ^14.2.7
|
||||
flutter_screenutil: ^5.9.3
|
||||
bootstrap_icons: ^1.11.3
|
||||
fl_chart: ^0.69.0
|
||||
google_fonts: ^6.2.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||