Profile UI and Api

This commit is contained in:
Vaibhav 2024-09-29 22:11:32 +05:30
parent c246d1cbeb
commit 76da563953
13 changed files with 594 additions and 538 deletions

View File

@ -1,110 +1,36 @@
import 'package:cheminova/controller/home_service.dart';
import 'package:cheminova/models/user_model.dart'; import 'package:cheminova/models/user_model.dart';
import 'package:cheminova/services/api_service.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
class HomeController extends GetxController { class HomeController extends GetxController {
final HomeService homeService = HomeService(); final ApiService _apiService = ApiService();
final Rx<UserProfile?> userProfile = Rx<UserProfile?>(null);
UserModel? user; final RxBool isLoading = false.obs;
final RxString error = ''.obs;
// var userModel = UserModel(
// id: '',
// uniqueId: '',
// name: '',
// email: '',
// phone: '',
// role: '',
// sbu: '',
// createdAt: '',
// updatedAt: '',
// ).obs; // Observable for UserModel
@override @override
void onInit() { void onInit() {
getUser();
super.onInit(); super.onInit();
fetchUserProfile();
} }
Future<void> getUser() async { Future<void> fetchUserProfile() async {
try { // isLoading.value = true;
print("Starting getUser function in controller"); error.value = '';
SharedPreferences prefs = await SharedPreferences.getInstance();
String? token = prefs.getString('token');
print("Token from SharedPreferences: $token"); // try {
final response = await _apiService.get('/api/rd-get-me');
HomeService homeService = HomeService(); if (response.statusCode == 200) {
print("Calling homeService.getUser"); userProfile.value = UserProfile.fromJson(response.data);
user = await homeService.getUser(token: token);
print("homeService.getUser completed. User: $user");
update();
if (user != null) {
print("User fetched successfully: $user");
} else { } else {
print('Failed to fetch user data'); error.value =
'Failed to load user profile. Status code: ${response.statusCode}';
} }
} catch (e) { // } catch (e) {
print("Error in getUser controller function: ${e.toString()}"); // error.value = 'An error occurred: $e';
} // } finally {
// isLoading.value = false;
// }
} }
} }
// import 'package:cheminova/controller/home_service.dart';
// import 'package:cheminova/models/user_model.dart';
// import 'package:get/get.dart';
// import 'package:shared_preferences/shared_preferences.dart';
//
// import '../notification_service.dart';
//
// class HomeController extends GetxController {
// final HomeService homeService = HomeService();
// NotificationServices notificationServices = NotificationServices();
//
//
//
// var userModel = UserModel(id: '', uniqueId: '', name: '', email: '', phone: '', role: '', sbu: '', createdAt: '', updatedAt: ''
//
// ).obs; // Observable for UserModel
//
// @override
// void onInit() {
// getUser();
// super.onInit();
// notificationServices.requestNotificationPermission();
// notificationServices.getDeviceToken().then((value) {
// print('Device Token: $value');
// fcmToken();
// });
// }
//
// Future<void> fcmToken() async {
// SharedPreferences prefs = await SharedPreferences.getInstance();
// String? token = prefs.getString('token');
// final fcmToken = await NotificationServices().getDeviceToken();
// print('fcmToken: $fcmToken');
// homeService.fcmToken({"fcmToken": fcmToken}, token!);
// }
//
// Future<void> getUser() async {
// SharedPreferences prefs = await SharedPreferences.getInstance();
//
// String? token = prefs.getString('token');
//
// userModel = (await homeService.getUser(token: token)) as dynamic;
//
//
// // if (userModel != null) {
// // if (userModel != null) {ddddd
// // userModel.value = userResponse as UserModel; // Update the userModel with API response
// // update(); // Notify GetX to rebuild widgets using GetBuilder/Obx
// // }
// }
// }
//

View File

@ -4,7 +4,7 @@ import 'package:cheminova/utils/show_snackbar.dart';
import '../utils/api_urls.dart'; import '../utils/api_urls.dart';
class HomeService { class HomeService {
Future<UserModel?> getUser({String? token}) async { Future<UserProfile?> getUser({String? token}) async {
try { try {
print("Starting getUser method in HomeService"); print("Starting getUser method in HomeService");
print("Token: $token"); print("Token: $token");
@ -40,7 +40,7 @@ class HomeService {
} }
print("Attempting to create UserModel from myData"); print("Attempting to create UserModel from myData");
final userModel = UserModel.fromJson(response['myData']); final userModel = UserProfile.fromJson(response['myData']);
print("UserModel created successfully: $userModel"); print("UserModel created successfully: $userModel");
return userModel; return userModel;
} catch (e) { } catch (e) {

View File

@ -1,76 +1,70 @@
class UserModel { class UserProfile {
final String id; bool? success;
final String uniqueId; String? message;
final String name; MyData? myData;
final String email;
final String mobileNumber;
final String designation;
final String userType;
final String? principalDistributer;
final String? addedBy;
final String? kyc;
final String? fcmToken;
final String createdAt;
final String updatedAt;
final String? mappedSC;
UserModel({ UserProfile({this.success, this.message, this.myData});
required this.id,
required this.uniqueId,
required this.name,
required this.email,
required this.mobileNumber,
required this.designation,
required this.userType,
this.principalDistributer,
this.addedBy,
this.kyc,
this.fcmToken,
required this.createdAt,
required this.updatedAt,
this.mappedSC,
});
factory UserModel.fromJson(Map<String, dynamic> json) { factory UserProfile.fromJson(Map<String, dynamic> json) {
return UserModel( return UserProfile(
success: json['success'],
message: json['message'],
myData: json['myData'] != null ? MyData.fromJson(json['myData']) : null,
);
}
}
class MyData {
String? id;
String? designation;
String? name;
String? email;
String? mobileNumber;
String? principalDistributer;
String? addedBy;
String? userType;
String? kyc;
String? fcmToken;
String? createdAt;
String? updatedAt;
String? mappedSC;
String? uniqueId;
int? v;
MyData(
{this.id,
this.designation,
this.name,
this.email,
this.mobileNumber,
this.principalDistributer,
this.addedBy,
this.userType,
this.kyc,
this.fcmToken,
this.createdAt,
this.updatedAt,
this.mappedSC,
this.uniqueId,
this.v});
factory MyData.fromJson(Map<String, dynamic> json) {
return MyData(
id: json['_id'], id: json['_id'],
uniqueId: json['uniqueId'], designation: json['designation'],
name: json['name'], name: json['name'],
email: json['email'], email: json['email'],
mobileNumber: json['mobile_number'], mobileNumber: json['mobile_number'],
designation: json['designation'],
userType: json['userType'],
principalDistributer: json['principal_distributer'], principalDistributer: json['principal_distributer'],
addedBy: json['addedBy'], addedBy: json['addedBy'],
userType: json['userType'],
kyc: json['kyc'], kyc: json['kyc'],
fcmToken: json['fcm_token'], fcmToken: json['fcm_token'],
createdAt: json['createdAt'], createdAt: json['createdAt'],
updatedAt: json['updatedAt'], updatedAt: json['updatedAt'],
mappedSC: json['mappedSC'], mappedSC: json['mappedSC'],
uniqueId: json['uniqueId'],
v: json['__v'],
); );
} }
Map<String, dynamic> toJson() {
return {
'_id': id,
'uniqueId': uniqueId,
'name': name,
'email': email,
'mobile_number': mobileNumber,
'designation': designation,
'userType': userType,
'principal_distributer': principalDistributer,
'addedBy': addedBy,
'kyc': kyc,
'fcm_token': fcmToken,
'createdAt': createdAt,
'updatedAt': updatedAt,
'mappedSC': mappedSC,
};
}
@override
String toString() {
return 'UserModel{id: $id, uniqueId: $uniqueId, name: $name, email: $email, mobileNumber: $mobileNumber, designation: $designation, userType: $userType, principalDistributer: $principalDistributer, addedBy: $addedBy, kyc: $kyc, fcmToken: $fcmToken, createdAt: $createdAt, updatedAt: $updatedAt, mappedSC: $mappedSC}';
}
} }

View File

@ -4,87 +4,75 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import '../../widgets/comman_background.dart'; import '../../widgets/comman_background.dart';
import '../../widgets/common_appbar.dart'; import '../../widgets/common_appbar.dart';
class ProfileScreen extends StatefulWidget { class ProfileScreen extends StatefulWidget {
// String? name; const ProfileScreen({super.key});
// final String uniqueId;
// final String email;
// final String mobileNumber;
// final String designation;
const ProfileScreen({
Key? key,
}) : super(key: key);
@override @override
State<ProfileScreen> createState() => _ProfileScreenState(); State<ProfileScreen> createState() => _ProfileScreenState();
} }
class _ProfileScreenState extends State<ProfileScreen> { class _ProfileScreenState extends State<ProfileScreen> {
final HomeController _homeController = Get.find();
final homecontroller = Get.put(HomeController());
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final user = homecontroller!.user; return Stack(children: [
return Stack( CommonBackground(
children: [
CommonBackground(
isFullWidth: true, isFullWidth: true,
child: Scaffold( child: Scaffold(
drawer: MyDrawer(), drawer: const MyDrawer(),
backgroundColor: Colors.transparent,
appBar: CommonAppBar(
title: const Text('Profile'),
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
elevation: 0, appBar: CommonAppBar(
actions: [ title: const Text('Profile'),
IconButton( backgroundColor: Colors.transparent,
onPressed: () { elevation: 0,
Navigator.pop(context); actions: [
}, IconButton(
icon: SvgPicture.asset( onPressed: () => Navigator.pop(context),
'assets/svg/back_arrow.svg', icon: SvgPicture.asset('assets/svg/back_arrow.svg'),
), padding: const EdgeInsets.only(right: 20))
padding: const EdgeInsets.only(right: 20), ]),
), body: Obx(() {
], if (_homeController.isLoading.value) {
), return const Center(child: CircularProgressIndicator());
body: SingleChildScrollView( } else if (_homeController.error.value.isNotEmpty) {
child: Column( return Center(child: Text(_homeController.error.value));
children: [ } else {
Container( final user = _homeController.userProfile.value;
padding: const EdgeInsets.all(20.0) return SingleChildScrollView(
.copyWith(top: 15, bottom: 30), child: Column(children: [
margin: const EdgeInsets.symmetric( Container(
horizontal: 30.0, vertical: 20.0), padding: const EdgeInsets.all(20.0)
decoration: BoxDecoration( .copyWith(top: 15, bottom: 30),
border: Border.all(color: Colors.white), margin: const EdgeInsets.symmetric(
color: const Color(0xffB4D1E5).withOpacity(0.9), horizontal: 30.0, vertical: 20.0),
borderRadius: BorderRadius.circular(26.0), decoration: BoxDecoration(
), border: Border.all(color: Colors.white),
child: Column( color: const Color(0xffB4D1E5).withOpacity(0.9),
crossAxisAlignment: CrossAxisAlignment.start, borderRadius: BorderRadius.circular(26.0),
children: [ ),
const SizedBox(height: 20), child: Column(
_buildProfileItem('Name', user!.name), crossAxisAlignment: CrossAxisAlignment.start,
_buildProfileItem('ID', user.uniqueId), children: [
_buildProfileItem('Email ID', user.email), const SizedBox(height: 20),
// _buildProfileItem('Mobile Number', user.phone), _buildProfileItem(
// _buildProfileItem('Designation', user.role), 'Name', user!.myData!.name ?? ''),
], _buildProfileItem(
), 'ID', user.myData!.uniqueId ?? ''),
), _buildProfileItem(
], 'Email ID', user.myData!.email ?? ''),
), _buildProfileItem('Mobile Number',
), user.myData!.mobileNumber ?? ''),
), _buildProfileItem(
), 'Designation', user.myData!.designation ?? '')
], ]))
); ]));
}
})))
]);
} }
Widget _buildProfileItem(String label, String value) { Widget _buildProfileItem(String label, String value) {

View File

@ -16,8 +16,13 @@ class LoginScreen extends StatefulWidget {
} }
class _LoginScreenState extends State<LoginScreen> { class _LoginScreenState extends State<LoginScreen> {
// Form key to manage the state of the form
final formKey = GlobalKey<FormState>(); final formKey = GlobalKey<FormState>();
// Instantiate the AuthController using GetX for state management
final authController = Get.put(AuthController()); final authController = Get.put(AuthController());
// Regular expressions for validating email and password formats
final String emailPattern = r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'; final String emailPattern = r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$';
final String passwordPattern = r'^.{6,}$'; // At least 6 characters final String passwordPattern = r'^.{6,}$'; // At least 6 characters
@ -27,6 +32,7 @@ class _LoginScreenState extends State<LoginScreen> {
body: Stack( body: Stack(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
children: [ children: [
// Background image and styling
Container( Container(
decoration: const BoxDecoration( decoration: const BoxDecoration(
image: DecorationImage( image: DecorationImage(
@ -43,14 +49,16 @@ class _LoginScreenState extends State<LoginScreen> {
height: Get.height * 0.7, height: Get.height * 0.7,
), ),
), ),
// Form for user login
SingleChildScrollView( SingleChildScrollView(
child: Form( child: Form(
key: formKey, key: formKey, // Link the form to the GlobalKey
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
SizedBox(height: Get.height * 0.1), SizedBox(height: Get.height * 0.1), // Spacer for top
// Welcome message
Container( Container(
margin: const EdgeInsets.symmetric(vertical: 20), margin: const EdgeInsets.symmetric(vertical: 20),
child: Text( child: Text(
@ -64,6 +72,7 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
), ),
), ),
// Logo container
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFFFFFFFF), color: const Color(0xFFFFFFFF),
@ -85,7 +94,8 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
), ),
), ),
SizedBox(height: Get.height * 0.05), SizedBox(height: Get.height * 0.05), // Spacer
// Login Card
Card( Card(
margin: const EdgeInsets.symmetric(horizontal: 24), margin: const EdgeInsets.symmetric(horizontal: 24),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@ -97,6 +107,7 @@ class _LoginScreenState extends State<LoginScreen> {
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
children: [ children: [
// Login icon
Container( Container(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
padding: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.only(bottom: 10),
@ -105,6 +116,7 @@ class _LoginScreenState extends State<LoginScreen> {
height: Get.height * 0.05, height: Get.height * 0.05,
), ),
), ),
// Login header
Container( Container(
padding: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.only(bottom: 10),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
@ -118,6 +130,7 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
), ),
), ),
// Subheader
Container( Container(
padding: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.only(bottom: 10),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
@ -131,10 +144,12 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
), ),
), ),
// Email input field
CommonTextFormField( CommonTextFormField(
controller: authController.emailController, controller: authController.emailController,
keyboardType: TextInputType.emailAddress, keyboardType: TextInputType.emailAddress,
validator: (value) { validator: (value) {
// Validate email input
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter your email id'; return 'Please enter your email id';
} }
@ -147,9 +162,11 @@ class _LoginScreenState extends State<LoginScreen> {
label: "Email", label: "Email",
), ),
const SizedBox(height: 15), const SizedBox(height: 15),
// Password input field
CommonTextFormField( CommonTextFormField(
controller: authController.passwordController, controller: authController.passwordController,
validator: (value) { validator: (value) {
// Validate password input
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'Please enter your password'; return 'Please enter your password';
} }
@ -158,12 +175,13 @@ class _LoginScreenState extends State<LoginScreen> {
} }
return null; return null;
}, },
obscureText: true, obscureText: true, // Hide password text
title: 'Password', title: 'Password',
maxLines: 1, maxLines: 1,
label: "Password", label: "Password",
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
// Link to forgot password screen
GestureDetector( GestureDetector(
onTap: () => onTap: () =>
Get.to(() => const ForgetPasswordScreen()), Get.to(() => const ForgetPasswordScreen()),
@ -179,13 +197,14 @@ class _LoginScreenState extends State<LoginScreen> {
), ),
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
// Login button with loading state
Obx( Obx(
() => CustomButton( () => CustomButton(
text: "Login", text: "Login",
onPressed: () { onPressed: () {
// Validate form and perform login action
if (formKey.currentState!.validate()) { if (formKey.currentState!.validate()) {
// Perform login action authController.login(); // Call login method
authController.login();
} }
}, },
isLoading: authController.isLoading.value, isLoading: authController.isLoading.value,

View File

@ -14,37 +14,40 @@ class VerifyOtpScreen extends StatefulWidget {
} }
class _VerifyOtpScreenState extends State<VerifyOtpScreen> { class _VerifyOtpScreenState extends State<VerifyOtpScreen> {
// Controller for managing the OTP input
final otpController = TextEditingController(); final otpController = TextEditingController();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true, // Extend body behind app bar for a seamless design
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent, // Transparent background for the app bar
elevation: 0, elevation: 0, // No shadow
leading: GestureDetector( leading: GestureDetector(
onTap: () => Get.back(), onTap: () => Get.back(), // Navigate back on tap
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), // Adjust the padding as needed padding: const EdgeInsets.all(8.0), // Padding for the back arrow icon
child: SizedBox( child: SizedBox(
width: 24, // Adjust the width as needed width: 24, // Icon width
height: 24, // Adjust the height as needed height: 24, // Icon height
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/svg/back_arrow.svg', 'assets/svg/back_arrow.svg', // Back arrow SVG asset
), ),
), ),
), ),
), ),
), ),
body: Stack( body: Stack(
alignment: Alignment.topCenter, alignment: Alignment.topCenter, // Align items to the top center
children: [ children: [
// Background image setup
Container( Container(
decoration: const BoxDecoration( decoration: const BoxDecoration(
image: DecorationImage( image: DecorationImage(
fit: BoxFit.cover, fit: BoxFit.cover,
image: AssetImage( image: AssetImage(
'assets/images/image_1.png', 'assets/images/image_1.png', // Background image asset
), ),
), ),
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
@ -53,33 +56,36 @@ class _VerifyOtpScreenState extends State<VerifyOtpScreen> {
), ),
), ),
child: SizedBox( child: SizedBox(
width: Get.width, width: Get.width, // Full width
height: Get.height * 0.7, height: Get.height * 0.7, // 70% height of the screen
), ),
), ),
// Main content area
Center( Center(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Card( child: Card(
margin: const EdgeInsets.symmetric(horizontal: 24), margin: const EdgeInsets.symmetric(horizontal: 24), // Margin for the card
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(19), borderRadius: BorderRadius.circular(19), // Rounded corners
side: const BorderSide(color: Color(0xFFFDFDFD)), side: const BorderSide(color: Color(0xFFFDFDFD)), // Border color
), ),
color: const Color(0xFFB4D1E5).withOpacity(0.9), color: const Color(0xFFB4D1E5).withOpacity(0.9), // Background color with opacity
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0), // Padding inside the card
child: Column( child: Column(
children: [ children: [
// Verification icon
Container( Container(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
padding: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.only(bottom: 10), // Padding below the icon
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/svg/verify_otp.svg', 'assets/svg/verify_otp.svg', // OTP verification icon asset
height: Get.height * 0.05, height: Get.height * 0.05, // Height of the icon
), ),
), ),
// Title for the OTP verification
Container( Container(
padding: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.only(bottom: 10), // Padding below the title
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
'Verification Code', 'Verification Code',
@ -91,8 +97,9 @@ class _VerifyOtpScreenState extends State<VerifyOtpScreen> {
), ),
), ),
), ),
// Subtext for OTP instructions
Container( Container(
padding: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.only(bottom: 10), // Padding below the subtext
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
'OTP has sent to your registered mobile number, Please verify', 'OTP has sent to your registered mobile number, Please verify',
@ -104,38 +111,40 @@ class _VerifyOtpScreenState extends State<VerifyOtpScreen> {
), ),
), ),
), ),
// Pin code input field for OTP
SizedBox( SizedBox(
width: Get.width * 0.8, width: Get.width * 0.8, // Width of the input field
child: PinCodeTextField( child: PinCodeTextField(
appContext: context, appContext: context,
length: 6, length: 6, // Length of the OTP
obscureText: false, obscureText: false, // Not obscured
animationType: AnimationType.fade, animationType: AnimationType.fade, // Fade animation
pinTheme: PinTheme( pinTheme: PinTheme(
shape: PinCodeFieldShape.box, shape: PinCodeFieldShape.box, // Shape of the pin fields
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5), // Corner radius
fieldHeight: 50, fieldHeight: 50, // Height of each pin field
fieldWidth: 40, fieldWidth: 40, // Width of each pin field
activeFillColor: Colors.white, activeFillColor: Colors.white, // Background color when active
inactiveFillColor: Colors.white, inactiveFillColor: Colors.white, // Background color when inactive
selectedFillColor: Colors.white, selectedFillColor: Colors.white, // Background color when selected
activeColor: Colors.blue, activeColor: Colors.blue, // Border color when active
inactiveColor: Colors.grey, inactiveColor: Colors.grey, // Border color when inactive
selectedColor: Colors.blue, selectedColor: Colors.blue, // Border color when selected
), ),
animationDuration: const Duration(milliseconds: 300), animationDuration: const Duration(milliseconds: 300), // Animation duration
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent, // Transparent background
enableActiveFill: true, enableActiveFill: true, // Enable active fill color
controller: otpController, controller: otpController, // Link the controller
onCompleted: (v) { onCompleted: (v) {
print("Completed: $v"); print("Completed: $v"); // Log when OTP is completed
}, },
onChanged: (value) { onChanged: (value) {
print(value); print(value); // Log changes to the input
}, },
), ),
), ),
const SizedBox(height: 30), const SizedBox(height: 30), // Spacer
// Resend OTP timer text
Container( Container(
alignment: Alignment.center, alignment: Alignment.center,
child: Text( child: Text(
@ -148,9 +157,10 @@ class _VerifyOtpScreenState extends State<VerifyOtpScreen> {
), ),
), ),
), ),
const SizedBox(height: 30), const SizedBox(height: 30), // Spacer
// Cancel button to go back
GestureDetector( GestureDetector(
onTap: () => Get.back(), onTap: () => Get.back(), // Navigate back on tap
child: Text( child: Text(
'Cancel', 'Cancel',
style: GoogleFonts.getFont( style: GoogleFonts.getFont(
@ -162,11 +172,12 @@ class _VerifyOtpScreenState extends State<VerifyOtpScreen> {
), ),
), ),
), ),
const SizedBox(height: 30), const SizedBox(height: 30), // Spacer
// Verify button to proceed
CustomButton( CustomButton(
text: "Verify", text: "Verify",
onPressed: () => Get.to( onPressed: () => Get.to(
() => const VerificationSuccessScreen(), () => const VerificationSuccessScreen(), // Navigate to success screen
), ),
), ),
], ],

View File

@ -13,6 +13,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
// HomeScreen displays various feature options (Product Catalogue, Order Tracking, etc.) as a grid of cards.
// It uses the GetX package for navigation and state management.
class HomeScreen extends StatefulWidget { class HomeScreen extends StatefulWidget {
const HomeScreen({super.key}); const HomeScreen({super.key});
@ -21,113 +23,143 @@ class HomeScreen extends StatefulWidget {
} }
class _HomeScreenState extends State<HomeScreen> { class _HomeScreenState extends State<HomeScreen> {
// HomeController is being initialized using GetX for state management.
final HomeController homeController = Get.put(HomeController()); final HomeController homeController = Get.put(HomeController());
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true, // The app bar extends behind the body content.
// AppBar configuration with transparent background and a custom menu icon
appBar: AppBar( appBar: AppBar(
centerTitle: true, centerTitle: true,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent, // AppBar background is transparent to blend with the background image.
elevation: 0, elevation: 0, // No shadow under the AppBar.
// Leading widget is a custom menu icon that opens the drawer when tapped.
leading: Builder( leading: Builder(
builder: (context) { builder: (context) {
return GestureDetector( return GestureDetector(
onTap: () => Scaffold.of(context).openDrawer(), onTap: () => Scaffold.of(context).openDrawer(), // Opens the drawer.
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/svg/menu.svg', 'assets/svg/menu.svg', // SVG asset for the menu icon.
), ),
), ),
); );
}, },
), ),
// Title in the AppBar.
title: const Text( title: const Text(
"Welcome", "Welcome",
), ),
), ),
// Drawer widget displayed on the side when the menu icon is tapped.
drawer: const MyDrawer(), drawer: const MyDrawer(),
// Stack widget to layer the background image and content on top.
body: Stack( body: Stack(
fit: StackFit.expand, fit: StackFit.expand, // Background image will fill the screen.
children: [ children: [
// Background image covering the entire screen.
Image.asset( Image.asset(
'assets/images/image_1.png', 'assets/images/image_1.png',
fit: BoxFit.cover, fit: BoxFit.cover, // The image is resized to cover the entire area.
), ),
// SafeArea widget to ensure the content is placed within safe boundaries.
SafeArea( SafeArea(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
// SingleChildScrollView allows scrolling if the content is larger than the screen.
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly, // Evenly spaces the rows of cards.
children: [ children: [
// Row with two HomeCard widgets for Product Catalogue and Order Tracking.
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly, // Cards are spaced evenly across the row.
children: [ children: [
// HomeCard widget with the title and navigation to the Product Catalog screen.
HomeCard( HomeCard(
title: 'Product Catalogue', title: 'Product Catalogue',
onTap: () => onTap: () =>
Get.to(() => const ProductCatalogScreen()), Get.to(() => const ProductCatalogScreen()), // Navigates to ProductCatalogScreen using GetX.
), ),
// HomeCard widget with the title and navigation to the Order Tracking screen.
HomeCard( HomeCard(
title: 'Order Tracking', title: 'Order Tracking',
onTap: () => Get.to( onTap: () => Get.to(
() => const OrderTrackingScreen(), () => const OrderTrackingScreen(), // Navigates to OrderTrackingScreen using GetX.
), ),
), ),
], ],
), ),
const SizedBox(height: 10),
const SizedBox(height: 10), // Adds vertical spacing between rows.
// Row with two HomeCard widgets for Order Management and Shipping Management.
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
HomeCard( HomeCard(
title: 'Order Management', title: 'Order Management',
onTap: () => Get.to( onTap: () => Get.to(
() => OrderManagementScreen(), () => OrderManagementScreen(), // Navigates to OrderManagementScreen.
), ),
), ),
HomeCard( HomeCard(
title: 'Shipping Management', title: 'Shipping Management',
onTap: () => Get.to( onTap: () => Get.to(
() => const ShippingManagementScreen(), () => const ShippingManagementScreen(), // Navigates to ShippingManagementScreen.
), ),
), ),
], ],
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
// Row with two HomeCard widgets for Inventory Management and Reporting & Analytics.
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
HomeCard( HomeCard(
title: 'Inventory Management', title: 'Inventory Management',
onTap: () => Get.to( onTap: () => Get.to(
() => const InventoryManagementScreen(), () => const InventoryManagementScreen(), // Navigates to InventoryManagementScreen.
), ),
), ),
HomeCard( HomeCard(
title: 'Reporting & Analytics', title: 'Reporting & Analytics',
onTap: () => Get.to( onTap: () => Get.to(
() => const ReportingAnalyticsScreen(), () => const ReportingAnalyticsScreen(), // Navigates to ReportingAnalyticsScreen.
), ),
), ),
], ],
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
// Row with two HomeCard widgets for Order Data Export and Retail Distributors Onboarding.
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [ children: [
HomeCard( HomeCard(
title: 'Order Data Export', title: 'Order Data Export',
onTap: () => Get.to( onTap: () => Get.to(
() => const OrderHistoryReportScreen(), () => const OrderHistoryReportScreen(), // Navigates to OrderHistoryReportScreen.
), ),
), ),
HomeCard( HomeCard(
title: 'Retail Distributors Onboarding', title: 'Retail Distributors Onboarding',
onTap: () => Get.to( onTap: () => Get.to(
() => const RetailDistributerOnBoardingScreen(), () => const RetailDistributerOnBoardingScreen(), // Navigates to RetailDistributerOnBoardingScreen.
), ),
), ),
], ],

View File

@ -1,4 +1,3 @@
import 'package:cheminova/screens/order/checkout_screen.dart'; import 'package:cheminova/screens/order/checkout_screen.dart';
import 'package:cheminova/widgets/my_drawer.dart'; import 'package:cheminova/widgets/my_drawer.dart';
import 'package:cheminova/widgets/product_card.dart'; import 'package:cheminova/widgets/product_card.dart';
@ -11,9 +10,11 @@ import '../../controller/cart_controller.dart';
import '../../models/oder_place_model.dart'; import '../../models/oder_place_model.dart';
import '../../models/product_model1.dart'; import '../../models/product_model1.dart';
// CartScreen represents the cart view in the application, where users can review
// products they have added, select/deselect them, and proceed to checkout.
class CartScreen extends StatefulWidget { class CartScreen extends StatefulWidget {
Product? productModel; Product? productModel; // Optional product model to add a product directly to the cart.
PlacedOrderModel? placedOrder; PlacedOrderModel? placedOrder; // Optional order placement model.
CartScreen({super.key, this.productModel, this.placedOrder}); CartScreen({super.key, this.productModel, this.placedOrder});
@ -22,31 +23,39 @@ class CartScreen extends StatefulWidget {
} }
class _CartScreenState extends State<CartScreen> { class _CartScreenState extends State<CartScreen> {
// CartController handles cart-related logic such as adding/removing products, selections, and totals.
final CartController _cartController = Get.find<CartController>(); final CartController _cartController = Get.find<CartController>();
bool _selectAll = true; // Default to true to select all products bool _selectAll = true; // Boolean flag to determine if all products are selected by default.
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// If a product model is passed when navigating to this screen, add it to the cart.
if (widget.productModel != null) { if (widget.productModel != null) {
_cartController.addToCart(widget.productModel!); _cartController.addToCart(widget.productModel!);
} }
// Ensure all products are pre-selected by default
// Initialize product selections to ensure all products are selected by default.
_cartController.initializeSelections(); _cartController.initializeSelections();
_checkIfAllSelected(); // Check if all products are selected by default
// Check if all products are selected and update the _selectAll flag accordingly.
_checkIfAllSelected();
} }
// Toggles the selection of all products in the cart.
void _toggleSelectAll(bool? value) { void _toggleSelectAll(bool? value) {
setState(() { setState(() {
_selectAll = value ?? false; _selectAll = value ?? false; // Update _selectAll based on the checkbox value.
_cartController.selectAllProducts(_selectAll); _cartController.selectAllProducts(_selectAll); // Select or deselect all products.
}); });
} }
// Check if all products in the cart are selected. Updates the _selectAll flag.
void _checkIfAllSelected() { void _checkIfAllSelected() {
// This function checks if all items are selected or not and updates _selectAll
setState(() { setState(() {
// If every product in the cart is selected, _selectAll is set to true.
_selectAll = _cartController.cartList.every( _selectAll = _cartController.cartList.every(
(product) => _cartController.selectedProducts.contains(product), (product) => _cartController.selectedProducts.contains(product),
); );
@ -57,62 +66,73 @@ class _CartScreenState extends State<CartScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
// Transparent AppBar with a menu icon and back button.
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent, // Transparent background.
elevation: 0, elevation: 0, // No elevation.
leading: Builder( leading: Builder(
builder: (context) { builder: (context) {
return GestureDetector( return GestureDetector(
onTap: () => Scaffold.of(context).openDrawer(), onTap: () => Scaffold.of(context).openDrawer(), // Open the drawer on tap.
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/svg/menu.svg', 'assets/svg/menu.svg', // SVG asset for the menu icon.
), ),
), ),
); );
}, },
), ),
actions: [ actions: [
// Back button to navigate to the previous screen.
GestureDetector( GestureDetector(
onTap: () => Get.back(), onTap: () => Get.back(), // Go back on tap.
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/svg/back_arrow.svg', 'assets/svg/back_arrow.svg', // SVG asset for the back icon.
), ),
), ),
), ),
], ],
title: const Center( title: const Center(
child: Text( child: Text(
"Cart", "Cart", // Title for the AppBar.
), ),
), ),
), ),
drawer: const MyDrawer(),
drawer: const MyDrawer(), // Drawer menu.
// Stack for the background image and the content above it.
body: Stack( body: Stack(
fit: StackFit.expand, fit: StackFit.expand, // Ensure the background image fills the entire screen.
children: [ children: [
// Background image that covers the entire screen.
Image.asset( Image.asset(
'assets/images/image_1.png', 'assets/images/image_1.png',
fit: BoxFit.cover, fit: BoxFit.cover, // Cover the entire screen with the image.
), ),
// SafeArea ensures content is within safe device boundaries.
SafeArea( SafeArea(
// Obx listens to changes in the cartList and updates the UI.
child: Obx(() { child: Obx(() {
// If the cart is empty, show an empty cart message and image.
if (_cartController.cartList.isEmpty) { if (_cartController.cartList.isEmpty) {
return Center( return Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Image.asset( Image.asset(
'assets/images/cart.png', 'assets/images/cart.png', // Display an empty cart image.
width: Get.width * 0.5, width: Get.width * 0.5,
height: Get.width * 0.5, height: Get.width * 0.5,
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
'Your Cart is empty', 'Your Cart is empty', // Message indicating the cart is empty.
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 24, fontSize: 24,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -123,11 +143,15 @@ class _CartScreenState extends State<CartScreen> {
), ),
); );
} }
// If there are items in the cart, show the cart list and summary.
return Column( return Column(
children: [ children: [
SizedBox( SizedBox(
height: Get.height * 0.02, height: Get.height * 0.02,
), ),
// Card widget for displaying the cart details and selection options.
Card( Card(
margin: const EdgeInsets.symmetric(horizontal: 18), margin: const EdgeInsets.symmetric(horizontal: 18),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@ -140,15 +164,15 @@ class _CartScreenState extends State<CartScreen> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// "Select All" Checkbox // Row for "Select All" checkbox and label.
Row( Row(
children: [ children: [
Checkbox( Checkbox(
value: _selectAll, value: _selectAll, // Checkbox value linked to _selectAll flag.
onChanged: _toggleSelectAll, onChanged: _toggleSelectAll, // Toggle all selections when changed.
), ),
Text( Text(
"Select All", "Select All", // Label for the select all checkbox.
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@ -156,30 +180,34 @@ class _CartScreenState extends State<CartScreen> {
), ),
], ],
), ),
// List of products in the cart.
SizedBox( SizedBox(
height: Get.height * 0.6, height: Get.height * 0.6,
child: ListView.builder( child: ListView.builder(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: _cartController.cartList.length, itemCount: _cartController.cartList.length, // Number of items in the cart.
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Row( return Row(
children: [ children: [
// Checkbox for individual product selection.
Checkbox( Checkbox(
value: _cartController.selectedProducts.contains( value: _cartController.selectedProducts.contains(
_cartController.cartList[index]), _cartController.cartList[index]),
onChanged: (value) { onChanged: (value) {
_cartController.toggleProductSelection( _cartController.toggleProductSelection(
_cartController.cartList[index], _cartController.cartList[index],
value!, value!, // Toggle product selection.
); );
_checkIfAllSelected(); // Check if all are selected after each toggle _checkIfAllSelected(); // Recheck if all products are selected.
}, },
), ),
// ProductCard displaying product details in the cart.
Expanded( Expanded(
child: ProductCard( child: ProductCard(
productModel: productModel: _cartController.cartList[index],
_cartController.cartList[index], isInCart: true, // Indicates this product is in the cart.
isInCart: true,
placedOrder: widget.placedOrder, placedOrder: widget.placedOrder,
), ),
), ),
@ -189,6 +217,8 @@ class _CartScreenState extends State<CartScreen> {
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
// Row displaying the subtotal amount.
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -200,10 +230,12 @@ class _CartScreenState extends State<CartScreen> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Obx(() => // Display the subtotal using an Obx to update automatically.
Text("${_cartController.subtotal.value}")), Obx(() => Text("${_cartController.subtotal.value}")),
], ],
), ),
// Row displaying the GST amount.
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -215,10 +247,11 @@ class _CartScreenState extends State<CartScreen> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Obx(() => Obx(() => Text("${_cartController.gstTotal.value}")),
Text("${_cartController.gstTotal.value}")),
], ],
), ),
// Row displaying the total amount (subtotal + GST).
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -230,25 +263,27 @@ class _CartScreenState extends State<CartScreen> {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
Obx(() => Text( Obx(() => Text("${_cartController.grandTotal.value}")),
"${_cartController.grandTotal.value}")),
], ],
), ),
], ],
), ),
), ),
), ),
SizedBox(height: Get.height * 0.020), SizedBox(height: Get.height * 0.020),
// Button to proceed to the checkout screen.
SizedBox( SizedBox(
width: Get.width * 0.9, width: Get.width * 0.9,
height: Get.height * 0.06, height: Get.height * 0.06,
child: ElevatedButton( child: ElevatedButton(
onPressed: () => Get.to(() => CheckoutScreen( onPressed: () => Get.to(() => CheckoutScreen(
selectedProducts: _cartController.selectedProducts, selectedProducts: _cartController.selectedProducts, // Pass selected products to CheckoutScreen.
)), )),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, foregroundColor: Colors.white,
backgroundColor: const Color(0xFF00784C), backgroundColor: const Color(0xFF00784C), // Green button for checkout.
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
@ -276,6 +311,7 @@ class _CartScreenState extends State<CartScreen> {
// import 'package:cheminova/models/oder_place_model.dart'; // import 'package:cheminova/models/oder_place_model.dart';
// import 'package:cheminova/models/product_model.dart'; // import 'package:cheminova/models/product_model.dart';
// import 'package:cheminova/screens/order/checkout_screen.dart'; // import 'package:cheminova/screens/order/checkout_screen.dart';

View File

@ -8,8 +8,8 @@ import '../../controller/cart_controller.dart';
import '../../widgets/my_drawer.dart'; import '../../widgets/my_drawer.dart';
import '../../widgets/product_card.dart'; import '../../widgets/product_card.dart';
import '../../controller/product_service.dart'; import '../../controller/product_service.dart';
import '../../models/product_model.dart'; // Import your ProductModel
// ProductCatalogScreen displays a catalog of products that users can browse and filter.
class ProductCatalogScreen extends StatefulWidget { class ProductCatalogScreen extends StatefulWidget {
const ProductCatalogScreen({super.key}); const ProductCatalogScreen({super.key});
@ -18,100 +18,107 @@ class ProductCatalogScreen extends StatefulWidget {
} }
class _ProductCatalogScreenState extends State<ProductCatalogScreen> { class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
final ProductService _productService = ProductService(); final ProductService _productService = ProductService(); // Service to fetch product data.
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController(); // Controller for scroll events.
final CartController cartController = Get.put(CartController()); final CartController cartController = Get.put(CartController()); // Cart controller for managing cart state.
List<Product> _products = []; // Use ProductModel here List<Product> _products = []; // List to hold the fetched products.
List<Map<String, dynamic>> _categories = []; List<Map<String, dynamic>> _categories = []; // List to hold product categories.
int _currentPage = 1; int _currentPage = 1; // Tracks the current page of products being fetched.
bool _isLoading = false; bool _isLoading = false; // Indicates if data is being loaded.
bool _hasMoreData = true; bool _hasMoreData = true; // Indicates if more data can be fetched.
String? _selectedCategory; String? _selectedCategory; // Tracks the currently selected category for filtering.
String? _selectedPriceRange; String? _selectedPriceRange; // Placeholder for selected price range filtering.
String? _selectedAvailability; String? _selectedAvailability; // Placeholder for selected availability filtering.
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_fetchCategories(); _fetchCategories(); // Fetch categories on initialization.
_fetchProducts(); _fetchProducts(); // Fetch initial products.
// Add listener to fetch more products when reaching the bottom of the scroll view.
_scrollController.addListener(() { _scrollController.addListener(() {
if (_scrollController.position.pixels == if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent && _scrollController.position.maxScrollExtent &&
!_isLoading && !_isLoading && _hasMoreData) {
_hasMoreData) {
_fetchMoreProducts(); _fetchMoreProducts();
} }
}); });
} }
// Fetch products from the server.
Future<void> _fetchProducts() async { Future<void> _fetchProducts() async {
setState(() { setState(() {
_isLoading = true; _isLoading = true; // Set loading to true while fetching data.
}); });
final category = _selectedCategory == 'All' ? null : _selectedCategory; final category = _selectedCategory == 'All' ? null : _selectedCategory; // Adjust category filter.
// Get products using the product service.
final products = await _productService.getProduct( final products = await _productService.getProduct(
_currentPage, category: category); _currentPage, category: category);
setState(() { setState(() {
if (products != null) { if (products != null) {
_products.addAll(products); // Assuming products is a List<ProductModel> _products.addAll(products); // Append fetched products to the list.
_hasMoreData = products.isNotEmpty; _hasMoreData = products.isNotEmpty; // Update the flag for more data availability.
} }
_isLoading = false; _isLoading = false; // Set loading to false after fetching data.
}); });
} }
// Fetch available product categories.
Future<void> _fetchCategories() async { Future<void> _fetchCategories() async {
final categories = await _productService.getCategory(); final categories = await _productService.getCategory(); // Fetch categories.
if (categories != null) { if (categories != null) {
setState(() { setState(() {
_categories = categories; _categories = categories; // Set the fetched categories.
_categories.insert(1, {'categoryName': 'All'}); _categories.insert(1, {'categoryName': 'All'}); // Add 'All' category option.
_selectedCategory = 'All'; _selectedCategory = 'All'; // Default selected category.
}); });
} }
} }
// Handle category changes when the user selects a new category.
void _onCategoryChanged(String? newCategory) { void _onCategoryChanged(String? newCategory) {
if (newCategory != null) { if (newCategory != null) {
setState(() { setState(() {
_selectedCategory = newCategory; _selectedCategory = newCategory; // Update selected category.
_products.clear(); _products.clear(); // Clear current product list for new fetch.
_currentPage = 1; _currentPage = 1; // Reset page counter.
}); });
_fetchProducts(); _fetchProducts(); // Fetch products for the selected category.
} }
} }
// Fetch additional products when scrolling to the bottom.
Future<void> _fetchMoreProducts() async { Future<void> _fetchMoreProducts() async {
if (!_isLoading && _hasMoreData) { if (!_isLoading && _hasMoreData) { // Ensure not already loading and more data is available.
setState(() { setState(() {
_isLoading = true; _isLoading = true; // Set loading to true while fetching more products.
_currentPage++; _currentPage++; // Increment the page number for next fetch.
}); });
await _fetchProducts(); await _fetchProducts(); // Fetch more products.
} }
} }
// Clear all filters and reset the product list.
void _clearFilters() { void _clearFilters() {
setState(() { setState(() {
_selectedCategory = null; _selectedCategory = null; // Reset category filter.
_selectedPriceRange = null; _selectedPriceRange = null; // Reset price range filter.
_selectedAvailability = null; _selectedAvailability = null; // Reset availability filter.
_products.clear(); _products.clear(); // Clear current product list.
_currentPage = 1; _currentPage = 1; // Reset page counter.
}); });
_fetchProducts(); _fetchProducts(); // Fetch products without filters.
} }
@override @override
void dispose() { void dispose() {
_scrollController.dispose(); _scrollController.dispose(); // Dispose of the scroll controller when done.
super.dispose(); super.dispose();
} }
@ -120,65 +127,67 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent, // Make the AppBar transparent.
elevation: 0, elevation: 0, // No shadow for the AppBar.
leading: Builder( leading: Builder(
builder: (context) { builder: (context) {
return GestureDetector( return GestureDetector(
onTap: () => Scaffold.of(context).openDrawer(), onTap: () => Scaffold.of(context).openDrawer(), // Open drawer on tap.
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/svg/menu.svg', 'assets/svg/menu.svg', // Menu icon.
), ),
), ),
); );
}, },
), ),
actions: [ actions: [
// Cart icon with count indicator.
GestureDetector( GestureDetector(
onTap: () => Get.to(CartScreen()), onTap: () => Get.to(CartScreen()), // Navigate to cart on tap.
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Stack( child: Stack(
children: [ children: [
Icon(Icons.shopping_cart, size: 30,), const Icon(Icons.shopping_cart, size: 30,), // Shopping cart icon.
// Cart count display // Cart count display
Positioned( Positioned(
right: 0, right: 0,
child: Obx(() => child: Obx(() =>
cartController.cartCount.value > 0 cartController.cartCount.value > 0
? Container( ? Container(
padding: EdgeInsets.all(4), padding: const EdgeInsets.all(4),
decoration: BoxDecoration( decoration: const BoxDecoration(
color: Colors.red, color: Colors.red,
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Text( child: Text(
'${cartController.cartCount.value}', '${cartController.cartCount.value}', // Display number of items in cart.
style: TextStyle( style: const TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 12, fontSize: 12,
), ),
), ),
) )
: SizedBox.shrink()), : const SizedBox.shrink()), // Hide if cart is empty.
), ),
], ],
), ),
), ),
), ),
], ],
title: Center( title: const Center(
child: const Text( child: Text(
"Product Catalogue", "Product Catalogue", // Title of the screen.
), ),
), ),
), ),
drawer: const MyDrawer(), drawer: const MyDrawer(), // Navigation drawer.
body: Stack( body: Stack(
fit: StackFit.expand, fit: StackFit.expand,
children: [ children: [
// Background image for the screen.
Image.asset( Image.asset(
'assets/images/image_1.png', 'assets/images/image_1.png',
fit: BoxFit.cover, fit: BoxFit.cover,
@ -187,12 +196,14 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
SizedBox(height: Get.height * 0.02), SizedBox(height: Get.height * 0.02), // Spacing.
// Search bar for products.
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0), padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: TextField( child: TextField(
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search Products", hintText: "Search Products", // Placeholder for search.
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
), ),
@ -201,7 +212,9 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
), ),
), ),
), ),
SizedBox(height: Get.height * 0.02), SizedBox(height: Get.height * 0.02), // Spacing.
// Card for filters and product listing.
Card( Card(
margin: const EdgeInsets.symmetric(horizontal: 18), margin: const EdgeInsets.symmetric(horizontal: 18),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@ -214,20 +227,22 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
// Filter section header.
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"Filter", "Filter", // Filter title.
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 16, fontSize: 16,
), ),
), ),
// Button to clear filters.
TextButton( TextButton(
onPressed: _clearFilters, onPressed: _clearFilters,
child: Text( child: Text(
"Clear Filter", "Clear Filter", // Clear filters button text.
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
color: Colors.red, color: Colors.red,
fontSize: 14, fontSize: 14,
@ -236,35 +251,37 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
), ),
], ],
), ),
// Dropdowns for filtering options.
SizedBox( SizedBox(
height: Get.height * 0.05, height: Get.height * 0.05,
child: ListView.builder( child: ListView.builder(
shrinkWrap: true, shrinkWrap: true,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: 3, itemCount: 3, // Number of filters (categories, etc.).
itemBuilder: (context, index) => itemBuilder: (context, index) =>
_buildFilterDropdown(index), _buildFilterDropdown(index), // Build filter dropdowns.
), ),
), ),
// List of products.
SizedBox( SizedBox(
height: Get.height * 0.6, height: Get.height * 0.6,
child: ListView.builder( child: ListView.builder(
controller: _scrollController, controller: _scrollController, // Attach scroll controller.
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
itemCount: _products.length + itemCount: _products.length + (_isLoading ? 1 : 0), // Show loading indicator if more products are being fetched.
(_isLoading ? 1 : 0),
itemBuilder: (context, index) { itemBuilder: (context, index) {
if (index >= _products.length) { if (index >= _products.length) {
print("Product length $_products"); print("Product length $_products");
return const Center( return const Center(
child: CircularProgressIndicator()); child: CircularProgressIndicator()); // Show loading indicator.
} }
// Display each product card.
return Padding( return Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(vertical: 8),
vertical: 8),
child: ProductCard( child: ProductCard(
productModel: _products[index], productModel: _products[index], // Use ProductModel here.
// Use ProductModel here
), ),
); );
}, },
@ -283,6 +300,7 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
); );
} }
// Build a dropdown for filtering based on the index.
Widget _buildFilterDropdown(int index) { Widget _buildFilterDropdown(int index) {
switch (index) { switch (index) {
case 0: case 0:
@ -295,57 +313,14 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
child: Text(category['categoryName']), child: Text(category['categoryName']),
); );
}).toList(), }).toList(),
hint: "Category", hint: "Category", // Dropdown hint for category selection.
); );
// case 1:
// return _buildStyledDropdown(
// value: _selectedPriceRange,
// onChanged: (value) {
// setState(() {
// _selectedPriceRange = value;
// });
// },
// items: [
// const DropdownMenuItem<String>(
// value: "Under ₹50",
// child: Text("Under ₹50"),
// ),
// const DropdownMenuItem<String>(
// value: "₹50 - ₹100",
// child: Text("₹50 - ₹100"),
// ),
// const DropdownMenuItem<String>(
// value: "Above ₹100",
// child: Text("Above ₹100"),
// ),
// ],
// hint: "Price Range",
// );
// case 2:
// return _buildStyledDropdown(
// value: _selectedAvailability,
// onChanged: (value) {
// setState(() {
// _selectedAvailability = value;
// });
// },
// items: [
// const DropdownMenuItem<String>(
// value: "In Stock",
// child: Text("In Stock"),
// ),
// const DropdownMenuItem<String>(
// value: "Out of Stock",
// child: Text("Out of Stock"),
// ),
// ],
// hint: "Availability",
// );
default: default:
return const SizedBox(); return const SizedBox(); // Return empty widget for unsupported indices.
} }
} }
// Build a styled dropdown widget.
Widget _buildStyledDropdown({ Widget _buildStyledDropdown({
required String? value, required String? value,
required ValueChanged<String?> onChanged, required ValueChanged<String?> onChanged,
@ -365,10 +340,9 @@ class _ProductCatalogScreenState extends State<ProductCatalogScreen> {
onChanged: onChanged, onChanged: onChanged,
items: items, items: items,
hint: Text(hint), hint: Text(hint),
icon: const Icon(Icons.arrow_drop_down), icon: const Icon(Icons.arrow_drop_down), // Dropdown arrow icon.
), ),
), ),
); );
} }
} }

View File

@ -9,9 +9,10 @@ import 'package:google_fonts/google_fonts.dart';
import '../../controller/cart_controller.dart'; import '../../controller/cart_controller.dart';
// ProductDetailScreen displays detailed information about a selected product.
class ProductDetailScreen extends StatefulWidget { class ProductDetailScreen extends StatefulWidget {
Product? productModel; Product? productModel; // Holds the product model data for display.
ProductModel? product; ProductModel? product; // Another product model (not used in this code).
ProductDetailScreen({super.key, this.product, this.productModel}); ProductDetailScreen({super.key, this.product, this.productModel});
@ -20,27 +21,30 @@ class ProductDetailScreen extends StatefulWidget {
} }
class _ProductDetailScreenState extends State<ProductDetailScreen> { class _ProductDetailScreenState extends State<ProductDetailScreen> {
final CartController _cartController = Get.put(CartController()); final CartController _cartController = Get.put(CartController()); // Controller for managing cart state.
// Capitalizes the first letter of the given text.
String capitalizeFirstLetter(String text) { String capitalizeFirstLetter(String text) {
if (text.isEmpty) return text; if (text.isEmpty) return text; // Return empty if the text is empty.
return text[0].toUpperCase() + text.substring(1).toLowerCase(); return text[0].toUpperCase() + text.substring(1).toLowerCase(); // Capitalize the first letter.
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true, // Extend the body behind the AppBar.
appBar: AppBar( appBar: AppBar(
centerTitle: true, centerTitle: true, // Center the title.
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent, // Make AppBar transparent.
elevation: 0, elevation: 0, // Remove shadow from AppBar.
leading: Builder( leading: Builder(
builder: (context) { builder: (context) {
return GestureDetector( return GestureDetector(
onTap: () => Scaffold.of(context).openDrawer(), onTap: () => Scaffold.of(context).openDrawer(), // Open drawer on tap.
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/svg/menu.svg', 'assets/svg/menu.svg', // Menu icon.
), ),
), ),
); );
@ -48,111 +52,115 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
), ),
actions: [ actions: [
GestureDetector( GestureDetector(
onTap: () => Get.back(), onTap: () => Get.back(), // Navigate back on tap.
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: SvgPicture.asset( child: SvgPicture.asset(
'assets/svg/back_arrow.svg', 'assets/svg/back_arrow.svg', // Back arrow icon.
), ),
), ),
), ),
], ],
title: const Text( title: const Text(
"Product Detail", "Product Detail", // Title of the screen.
), ),
), ),
drawer: const MyDrawer(), drawer: const MyDrawer(), // Navigation drawer.
body: Stack( body: Stack(
fit: StackFit.expand, fit: StackFit.expand, // Expand the stack to fit the screen.
children: [ children: [
Image.asset( Image.asset(
'assets/images/image_1.png', 'assets/images/image_1.png', // Background image.
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
SafeArea( SafeArea(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, // Align items to start.
children: [ children: [
SizedBox( SizedBox(height: Get.height * 0.02), // Spacing above the card.
height: Get.height * 0.02,
), // Card to display product details.
Card( Card(
margin: const EdgeInsets.symmetric(horizontal: 16), margin: const EdgeInsets.symmetric(horizontal: 16), // Horizontal margin.
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(19), borderRadius: BorderRadius.circular(19), // Rounded corners.
side: const BorderSide(color: Color(0xFFFDFDFD)), side: const BorderSide(color: Color(0xFFFDFDFD)), // Border color.
), ),
color: const Color(0xFFB4D1E5).withOpacity(0.9), color: const Color(0xFFB4D1E5).withOpacity(0.9), // Background color of the card.
child: Padding( child: Padding(
padding: const EdgeInsets.all(12.0), padding: const EdgeInsets.all(12.0), // Padding inside the card.
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min, // Minimize the size of the column.
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, // Align items to start.
children: [ children: [
// Product image section.
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Container( child: Container(
height: Get.height * 0.4, height: Get.height * 0.4, // Height of the image container.
width: Get.width * 0.8, width: Get.width * 0.8, // Width of the image container.
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(
width: 4, width: 4,
color: Colors.white, color: Colors.white, // Border color.
), ),
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15), // Rounded corners for the container.
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10), // Clip the corners of the image.
child: Image.asset("assets/images/product.png", fit: BoxFit.cover,), child: Image.asset(
// Image.asset( "assets/images/product.png", // Product image.
// widget.product.image, fit: BoxFit.cover, // Cover the container.
// fit: BoxFit.cover, ),
// ),
), ),
), ),
), ),
// Product name row.
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const Text("Product Name ",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 16),), const Text("Product Name ", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)), // Label for product name.
Text( Text(
capitalizeFirstLetter(widget.productModel!.name), capitalizeFirstLetter(widget.productModel!.name), // Display product name.
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 16, fontSize: 16,
// fontWeight: FontWeight.w600,
color: Colors.black, color: Colors.black,
), ),
), ),
], ],
), ),
), ),
// Product price row.
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const Text("Price ",style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold),), const Text("Price ", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), // Label for product price.
Text( Text(
"${widget.productModel!.price.toString()}", "${widget.productModel!.price.toString()}", // Display product price.
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 16, fontSize: 16,
//fontWeight: FontWeight.w800,
color: Colors.black, color: Colors.black,
), ),
), ),
], ],
), ),
), ),
// Product category row.
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const Text("Category ",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 16),), const Text("Category ", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)), // Label for category.
Text( Text(
capitalizeFirstLetter(widget.productModel!.category.categoryName), capitalizeFirstLetter(widget.productModel!.category.categoryName), // Display category name.
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@ -162,14 +170,17 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
], ],
), ),
), ),
const SizedBox(height: 8),
const SizedBox(height: 8), // Spacing between rows.
// Product description row.
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: Row( child: Row(
children: [ children: [
const Text("Description",style: TextStyle(fontWeight: FontWeight.bold,fontSize: 16)), const Text("Description", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)), // Label for description.
Text( Text(
capitalizeFirstLetter(widget.productModel!.description), capitalizeFirstLetter(widget.productModel!.description), // Display product description.
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
@ -183,25 +194,28 @@ class _ProductDetailScreenState extends State<ProductDetailScreen> {
), ),
), ),
), ),
SizedBox(height: Get.height * 0.04),
SizedBox(height: Get.height * 0.04), // Spacing below the card.
// Add to cart button.
SizedBox( SizedBox(
width: Get.width * 0.9, width: Get.width * 0.9,
height: Get.height * 0.06, height: Get.height * 0.06,
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
// Pass the product data to the CartScreen // Add the product to the cart and show a snackbar notification.
_cartController.addToCart(widget.productModel!); _cartController.addToCart(widget.productModel!);
showSnackbar("Product successfully added to your cart"); showSnackbar("Product successfully added to your cart"); // Display success message.
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
foregroundColor: Colors.white, foregroundColor: Colors.white, // Text color.
backgroundColor: const Color(0xFF00784C), backgroundColor: const Color(0xFF00784C), // Button background color.
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10), // Rounded corners for the button.
), ),
), ),
child: Text( child: Text(
"Add To Cart", "Add To Cart", // Button text.
style: GoogleFonts.roboto( style: GoogleFonts.roboto(
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,

View File

@ -0,0 +1,32 @@
import 'package:cheminova/services/app_interceptor.dart';
import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
class ApiService {
final Dio _dio;
ApiService() : _dio = Dio(BaseOptions(baseUrl: 'https://api.cnapp.co.in')) {
_dio.interceptors.add(AuthInterceptor());
_dio.interceptors.add(PrettyDioLogger());
}
Future<Response> get(String path) async {
try {
return await _dio.get(path);
} on DioException catch (e) {
return _handleError(e);
}
}
Future<Response> _handleError(DioException e) async {
if (e.response != null) {
return e.response!;
} else {
return Response(
requestOptions: RequestOptions(path: ''),
statusCode: 500,
data: {'message': 'An unexpected error occurred'},
);
}
}
}

View File

@ -0,0 +1,29 @@
import 'package:dio/dio.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthInterceptor extends Interceptor {
@override
void onRequest(
RequestOptions options, RequestInterceptorHandler handler) async {
final prefs = await SharedPreferences.getInstance();
final token = prefs.getString('token');
if (token != null) {
options.headers['Authorization'] = 'Bearer $token';
}
handler.next(options);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
// Handle the response if needed
handler.next(response);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
if (err.response?.statusCode == 401) {}
return handler.next(err);
}
}

View File

@ -15,7 +15,8 @@ class MyDrawer extends StatefulWidget {
} }
class _MyDrawerState extends State<MyDrawer> { class _MyDrawerState extends State<MyDrawer> {
final homeController = Get.put(HomeController()); final HomeController _homeController = Get.find();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Drawer( return Drawer(
@ -24,38 +25,40 @@ class _MyDrawerState extends State<MyDrawer> {
children: <Widget>[ children: <Widget>[
SizedBox( SizedBox(
height: 150, height: 150,
child:( child: Obx(() {
DrawerHeader( if (_homeController.isLoading.value) {
return const Center(child: CircularProgressIndicator());
} else if (_homeController.error.value.isNotEmpty) {
return Center(child: Text(_homeController.error.value));
} else {
final user = _homeController.userProfile.value;
return DrawerHeader(
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Colors.black87, color: Colors.black87,
), ),
child: GetBuilder( child: Column(
init: homeController, crossAxisAlignment: CrossAxisAlignment.start,
builder: (controller) { mainAxisAlignment: MainAxisAlignment.start,
return Column( children: [
crossAxisAlignment: CrossAxisAlignment.start, Text(
mainAxisAlignment: MainAxisAlignment.start, user!.myData!.name ?? "username",
children: [ style: const TextStyle(
Text( color: Colors.white,
controller.user?.name?? "username", fontSize: 18,
style: const TextStyle( ),
color: Colors.white, ),
fontSize: 18, Text(
), user!.myData!.uniqueId ?? 'Employee ID',
), style: const TextStyle(
Text( color: Colors.white,
controller.user?.uniqueId?? 'Employee ID', fontSize: 20,
style: const TextStyle( ),
color: Colors.white, ),
fontSize: 20, ],
),
),
],
);
}
), ),
) );
), }
}),
), ),
ListTile( ListTile(
leading: const Icon(Icons.home), leading: const Icon(Icons.home),
@ -65,15 +68,13 @@ class _MyDrawerState extends State<MyDrawer> {
ListTile( ListTile(
leading: const Icon(Icons.account_circle), leading: const Icon(Icons.account_circle),
title: const Text('Profile'), title: const Text('Profile'),
onTap: () { onTap: () => Get.to(() => const ProfileScreen()),
Get.to(ProfileScreen());
},
), ),
ListTile( ListTile(
leading: const Icon(Icons.settings), leading: const Icon(Icons.settings),
title: const Text('Change Password'), title: const Text('Change Password'),
onTap: () { onTap: () {
Get.to(ChangePasswordScreen()); Get.to(const ChangePasswordScreen());
}, },
), ),
ListTile( ListTile(