diff --git a/agrilink_vocpro/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/agrilink_vocpro/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index db77bb4..63e293f 100644 Binary files a/agrilink_vocpro/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/agrilink_vocpro/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/agrilink_vocpro/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/agrilink_vocpro/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b7..54b80a1 100644 Binary files a/agrilink_vocpro/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/agrilink_vocpro/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/agrilink_vocpro/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/agrilink_vocpro/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 09d4391..60a08cf 100644 Binary files a/agrilink_vocpro/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/agrilink_vocpro/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/agrilink_vocpro/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/agrilink_vocpro/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d..fb78396 100644 Binary files a/agrilink_vocpro/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/agrilink_vocpro/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/agrilink_vocpro/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/agrilink_vocpro/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372e..04150c4 100644 Binary files a/agrilink_vocpro/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/agrilink_vocpro/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/agrilink_vocpro/assets/images/app_logo.png b/agrilink_vocpro/assets/images/app_logo.png new file mode 100644 index 0000000..33cb4c2 Binary files /dev/null and b/agrilink_vocpro/assets/images/app_logo.png differ diff --git a/agrilink_vocpro/lib/core/constant/app_color.dart b/agrilink_vocpro/lib/core/constant/app_color.dart index db96314..3bd1d45 100644 --- a/agrilink_vocpro/lib/core/constant/app_color.dart +++ b/agrilink_vocpro/lib/core/constant/app_color.dart @@ -11,4 +11,5 @@ class AppColor { static const Color greenTextDark = Color(0xFF00913A); static const Color textDisable = Color(0xFFBDBDBD); + static const Color textDark = Color(0xFF4B4B51); } diff --git a/agrilink_vocpro/lib/core/constant/app_theme.dart b/agrilink_vocpro/lib/core/constant/app_theme.dart index 0cdc498..39412ed 100644 --- a/agrilink_vocpro/lib/core/constant/app_theme.dart +++ b/agrilink_vocpro/lib/core/constant/app_theme.dart @@ -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, ); diff --git a/agrilink_vocpro/lib/core/route/app_route.dart b/agrilink_vocpro/lib/core/route/app_route.dart new file mode 100644 index 0000000..3ecd3a0 --- /dev/null +++ b/agrilink_vocpro/lib/core/route/app_route.dart @@ -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}'), + ), + ), + ); +} diff --git a/agrilink_vocpro/lib/core/state/result_state.dart b/agrilink_vocpro/lib/core/state/result_state.dart index bcb3492..47b417d 100644 --- a/agrilink_vocpro/lib/core/state/result_state.dart +++ b/agrilink_vocpro/lib/core/state/result_state.dart @@ -1,7 +1,7 @@ enum ResultState { initial, loading, - noData, hasData, + noData, error, } diff --git a/agrilink_vocpro/lib/core/widgets/app_button.dart b/agrilink_vocpro/lib/core/widgets/app_button.dart index 31cc28e..8fc1818 100644 --- a/agrilink_vocpro/lib/core/widgets/app_button.dart +++ b/agrilink_vocpro/lib/core/widgets/app_button.dart @@ -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), diff --git a/agrilink_vocpro/lib/core/widgets/app_textfield.dart b/agrilink_vocpro/lib/core/widgets/app_textfield.dart index 3f37602..bac5ea9 100644 --- a/agrilink_vocpro/lib/core/widgets/app_textfield.dart +++ b/agrilink_vocpro/lib/core/widgets/app_textfield.dart @@ -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), ); } } diff --git a/agrilink_vocpro/lib/features/auth/provider/auth_provider.dart b/agrilink_vocpro/lib/features/auth/provider/auth_provider.dart new file mode 100644 index 0000000..2896c42 --- /dev/null +++ b/agrilink_vocpro/lib/features/auth/provider/auth_provider.dart @@ -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(); + } +} diff --git a/agrilink_vocpro/lib/features/auth/view/login_screen.dart b/agrilink_vocpro/lib/features/auth/view/login_screen.dart index e69de29..fd99e32 100644 --- a/agrilink_vocpro/lib/features/auth/view/login_screen.dart +++ b/agrilink_vocpro/lib/features/auth/view/login_screen.dart @@ -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(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'), + ], + ); + }), + ), + ), + ); + } +} diff --git a/agrilink_vocpro/lib/features/humidity/view/humidity_screen.dart b/agrilink_vocpro/lib/features/home/pages/humidity/view/humidity_screen.dart similarity index 68% rename from agrilink_vocpro/lib/features/humidity/view/humidity_screen.dart rename to agrilink_vocpro/lib/features/home/pages/humidity/view/humidity_screen.dart index e77e78d..be3c6fc 100644 --- a/agrilink_vocpro/lib/features/humidity/view/humidity_screen.dart +++ b/agrilink_vocpro/lib/features/home/pages/humidity/view/humidity_screen.dart @@ -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), ], diff --git a/agrilink_vocpro/lib/features/humidity/widgets/circle_chart.dart b/agrilink_vocpro/lib/features/home/pages/humidity/widgets/circle_chart.dart similarity index 82% rename from agrilink_vocpro/lib/features/humidity/widgets/circle_chart.dart rename to agrilink_vocpro/lib/features/home/pages/humidity/widgets/circle_chart.dart index aafa5c1..bb515bc 100644 --- a/agrilink_vocpro/lib/features/humidity/widgets/circle_chart.dart +++ b/agrilink_vocpro/lib/features/home/pages/humidity/widgets/circle_chart.dart @@ -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 createState() => _CircleChartState(); @@ -17,7 +21,7 @@ class _CircleChartState extends State { 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 { 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 { ); } - List _createSections(double humidityPercentage) { + List _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 { ), PieChartSectionData( color: Colors.white24, - value: 100 - humidityPercentage, + value: 100 - percentage, title: '', radius: 50, ), @@ -105,6 +108,6 @@ class _CircleChartState extends State { Color _getAnimatedColor(double percentage) { return Color.lerp( - Colors.green, Colors.blue, percentage / widget.humidityPercentage)!; + Colors.green, Colors.blue, percentage / widget.percentage)!; } } diff --git a/agrilink_vocpro/lib/features/home/pages/soil_moisture/view/soil_moisture_screen.dart b/agrilink_vocpro/lib/features/home/pages/soil_moisture/view/soil_moisture_screen.dart new file mode 100644 index 0000000..b7ea90e --- /dev/null +++ b/agrilink_vocpro/lib/features/home/pages/soil_moisture/view/soil_moisture_screen.dart @@ -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), + ], + ), + ), + ); + } +} diff --git a/agrilink_vocpro/lib/features/home/pages/temperature/view/temperature_screen.dart b/agrilink_vocpro/lib/features/home/pages/temperature/view/temperature_screen.dart new file mode 100644 index 0000000..7cf42b1 --- /dev/null +++ b/agrilink_vocpro/lib/features/home/pages/temperature/view/temperature_screen.dart @@ -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(Colors.red), + ), + )), + const SizedBox(height: 16), + ], + ), + ), + ); + } +} diff --git a/agrilink_vocpro/lib/features/home/view/home_screen.dart b/agrilink_vocpro/lib/features/home/view/home_screen.dart index dc54f4f..578c2a1 100644 --- a/agrilink_vocpro/lib/features/home/view/home_screen.dart +++ b/agrilink_vocpro/lib/features/home/view/home_screen.dart @@ -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(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, ) ], ) diff --git a/agrilink_vocpro/lib/features/splash/view/splash_screen.dart b/agrilink_vocpro/lib/features/splash/view/splash_screen.dart index f63c3ff..b5e41bb 100644 --- a/agrilink_vocpro/lib/features/splash/view/splash_screen.dart +++ b/agrilink_vocpro/lib/features/splash/view/splash_screen.dart @@ -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 { + bool isLoggedIn = false; + + @override + void initState() { + super.initState(); + _initialize(); + } + + Future _initialize() async { + // final authProvider = Provider.of(context, listen: false); + // bool isLoggedIn = await _checkLoginStatus(authProvider); + _navigateAfterSplash(isLoggedIn); + } + + // Future _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, + ), + ), + ), + ); } } diff --git a/agrilink_vocpro/lib/main.dart b/agrilink_vocpro/lib/main.dart index 7f21b6a..dee1ef1 100644 --- a/agrilink_vocpro/lib/main.dart +++ b/agrilink_vocpro/lib/main.dart @@ -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, ), ); } diff --git a/agrilink_vocpro/macos/Flutter/GeneratedPluginRegistrant.swift b/agrilink_vocpro/macos/Flutter/GeneratedPluginRegistrant.swift index 724bb2a..b8e2b22 100644 --- a/agrilink_vocpro/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/agrilink_vocpro/macos/Flutter/GeneratedPluginRegistrant.swift @@ -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")) } diff --git a/agrilink_vocpro/pubspec.lock b/agrilink_vocpro/pubspec.lock index 72be173..f50baf4 100644 --- a/agrilink_vocpro/pubspec.lock +++ b/agrilink_vocpro/pubspec.lock @@ -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: diff --git a/agrilink_vocpro/pubspec.yaml b/agrilink_vocpro/pubspec.yaml index 87c73e6..015adc8 100644 --- a/agrilink_vocpro/pubspec.yaml +++ b/agrilink_vocpro/pubspec.yaml @@ -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: