base_project

This commit is contained in:
2026-09-19 03:57:06 +00:00
commit e497faa322
1528 changed files with 79821 additions and 0 deletions
@@ -0,0 +1,524 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import '../../Utils/image_constant.dart';
import '../../Utils/size_utils.dart';
import '../../providers/token_manager.dart';
import '../../resources/api_constants.dart';
import '../../theme/app_style.dart';
import '../../widgets/app_bar/appbar_image.dart';
import '../../widgets/app_bar/appbar_title.dart';
import '../../widgets/app_bar/custom_app_bar.dart';
import '../../widgets/custom_button.dart';
import '../../widgets/custom_text_form_field.dart';
import '../Login Screen/login_screen.dart';
import '../LogoutService/Logoutservice.dart';
import 'apiserviceprofilemanagement.dart';
import 'package:http/http.dart' as http;
import 'changepassword.dart';
class ProfileSettingsScreen extends StatefulWidget {
final Map<String, dynamic> userData;
ProfileSettingsScreen({required this.userData});
@override
_ProfileSettingsScreenState createState() => _ProfileSettingsScreenState();
}
class _ProfileSettingsScreenState extends State<ProfileSettingsScreen> {
ApiServiceProfileManagement apiService = ApiServiceProfileManagement();
String? fetchedimageurl =
'http://43.205.154.152:30165/assets/images/profile-icon.png';
Uint8List? _imageBytes; // Uint8List to store the image data
String? _imageFileName;
final _formKey = GlobalKey<FormState>();
TextEditingController fullNameController = TextEditingController();
TextEditingController pronounsController = TextEditingController();
TextEditingController roleController = TextEditingController();
TextEditingController departmentController = TextEditingController();
TextEditingController emailController = TextEditingController();
TextEditingController aboutMeController = TextEditingController();
@override
void initState() {
super.initState();
//fetchProfileImageData();
fetchUserProfileData();
}
Future<void> _uploadImageFile() async {
final imagePicker = ImagePicker();
try {
final pickedImage =
await imagePicker.pickImage(source: ImageSource.gallery);
if (pickedImage != null) {
final imageBytes = await pickedImage.readAsBytes();
setState(() {
_imageBytes = imageBytes;
_imageFileName = pickedImage.name; // Store the file name
});
}
} catch (e) {
print(e);
}
}
//api/user-profile
Future<void> fetchUserProfileData() async {
final token = await TokenManager.getToken();
final String baseUrl = ApiConstants.baseUrl;
final String apiUrl = '$baseUrl/api/user-profile';
try {
final response = await http.get(
Uri.parse(apiUrl),
headers: {
'Authorization': 'Bearer $token',
},
);
if (response.statusCode == 401) {
LogoutService.logout();
}
if (response.statusCode >= 200 && response.statusCode <= 209) {
final Map<String, dynamic> jsonData = json.decode(response.body);
setState(() {
fullNameController.text =
jsonData['fullName'] != null ? jsonData['fullName'] : '';
pronounsController.text =
jsonData['pronouns'] != null ? jsonData['pronouns'] : '';
roleController.text =
jsonData['role'] != null ? jsonData['role'] : '';
departmentController.text =
jsonData['department'] != null ? jsonData['department'] : '';
emailController.text =
jsonData['email'] != null ? jsonData['email'] : '';
aboutMeController.text =
jsonData['about'] != null ? jsonData['about'] : '';
});
} else {
throw Exception('Failed to load data: ${response.statusCode}');
}
} catch (e) {
throw Exception('Failed to load data: $e');
}
}
Future<void> fetchProfileImageData() async {
final token = await TokenManager.getToken();
final String baseUrl = ApiConstants.baseUrl;
final String apiUrl = '$baseUrl/api/retrieve-image';
try {
final response = await http.get(
Uri.parse(apiUrl),
headers: {
'Authorization': 'Bearer $token',
},
);
if (response.statusCode == 401) {
LogoutService.logout();
}
if (response.statusCode >= 200 && response.statusCode <= 209) {
final Map<String, dynamic> jsonData = json.decode(response.body);
final trustedImageUrl = Uri.dataFromString(jsonData['image'],
mimeType: 'image/*', encoding: Encoding.getByName('utf-8'))
.toString();
fetchedimageurl = trustedImageUrl;
} else {
throw Exception('Failed to load data: ${response.statusCode}');
}
} catch (e) {
throw Exception('Failed to load data: $e');
}
}
Future<void> _submitImage() async {
if (_imageBytes == null) {
// Show an error message if no image is selected
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Error'),
content: Text('Please select an image.'),
actions: [
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
return;
}
if (_imageFileName == null) {
// Handle the case where _imageFileName is null (no file name provided)
print('File name is missing.');
return;
}
try {
final token = await TokenManager.getToken();
await apiService.createFile(_imageBytes!, _imageFileName!, token!);
} catch (e) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Error'),
content: Text('Failed to upload image: $e'),
actions: [
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
Future<void> _updateProfile() async {
if (_formKey.currentState!.validate()) {
// Create a JSON object with the form data
final profileData = {
'fullName': fullNameController.text,
'pronouns': pronounsController.text,
'role': roleController.text,
'department': departmentController.text,
'email': emailController.text,
'aboutMe': aboutMeController.text,
};
//api/user-profile
final token = await TokenManager.getToken();
final String baseUrl = ApiConstants.baseUrl;
final String apiUrl = '$baseUrl/api/user-profile';
try {
final response = await http.put(Uri.parse(apiUrl),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
body: json.encode(profileData));
if (response.statusCode == 401) {
LogoutService.logout();
}
if (response.statusCode <= 209) {
print("success");
Navigator.of(context).pop();
} else {
print(response.statusCode);
}
} catch (e) {
throw Exception('Failed to Update: $e');
}
}
}
Future<void> _logoutUser() async {
try {
String logouturl = "${ApiConstants.baseUrl}/token/logout";
var response = await http.get(Uri.parse(logouturl));
if (response.statusCode <= 209) {
// ignore: use_build_context_synchronously
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),
(route) => false, // Remove all routes from the stack
);
} else {
const Text('failed to logout');
}
} catch (error) {
print('Error occurred during logout: $error');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
height: getVerticalSize(49),
leadingWidth: 40,
leading: AppbarImage(
height: getSize(24),
width: getSize(24),
svgPath: ImageConstant.imgArrowleftBlueGray900,
margin: getMargin(left: 16, top: 12, bottom: 13),
onTap: () {
Navigator.pop(context);
}),
centerTitle: true,
title: AppbarTitle(text: "My Profile Settings")),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
// Section: Show Profile Photo
Center(
child: Column(
children: [
CircleAvatar(
radius: 70, // Adjust as needed
backgroundImage: NetworkImage(
"$fetchedimageurl"), // Replace with your API URL
),
SizedBox(height: 10),
CustomButton(
height: getVerticalSize(50),
text: _imageBytes == null
? "Pick a Profile Photo"
: 'Upload Success',
margin: getMargin(top: 24, bottom: 5),
onTap: () async {
if (_imageBytes != null) {
_submitImage();
} else {
_uploadImageFile();
}
},
),
],
),
),
SizedBox(height: 20),
// Section: Profile Form
Text(
'Your Profile Information',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
SizedBox(height: 10),
Form(
key: _formKey,
child: Column(
children: [
Padding(
padding: getPadding(top: 19),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Your Full Name",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: AppStyle.txtGilroyMedium16Bluegray900),
CustomTextFormField(
focusNode: FocusNode(),
controller: fullNameController,
hintText: "Enter Full Name",
validator: (value) {
if (value!.isEmpty) {
return 'Please enter your full name';
}
return null;
},
onChanged: (value) {
fullNameController.text = value;
},
margin: getMargin(top: 6))
])),
Padding(
padding: getPadding(top: 19),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Pronouns",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: AppStyle.txtGilroyMedium16Bluegray900),
CustomTextFormField(
focusNode: FocusNode(),
hintText: "Enter Pronouns",
controller: pronounsController,
onChanged: (value) {
pronounsController.text = value;
},
margin: getMargin(top: 6))
])),
Padding(
padding: getPadding(top: 19),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Role",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: AppStyle.txtGilroyMedium16Bluegray900),
CustomTextFormField(
focusNode: FocusNode(),
hintText: "Enter Role",
controller: roleController,
onChanged: (value) {
roleController.text = value;
},
margin: getMargin(top: 6))
])),
Padding(
padding: getPadding(top: 19),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Department or Team",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: AppStyle.txtGilroyMedium16Bluegray900),
CustomTextFormField(
focusNode: FocusNode(),
hintText: "Enter Department or Team",
controller: departmentController,
onChanged: (value) {
departmentController.text = value;
},
margin: getMargin(top: 6))
])),
Padding(
padding: getPadding(top: 19),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Email",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: AppStyle.txtGilroyMedium16Bluegray900),
CustomTextFormField(
focusNode: FocusNode(),
hintText: "Enter Email",
controller: emailController,
validator: (value) {
if (value!.isEmpty || !value!.contains('@')) {
return 'Please enter a valid email address';
}
return null;
},
onChanged: (value) {
emailController.text = value;
},
margin: getMargin(top: 6))
])),
Padding(
padding: getPadding(top: 19),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("About Me",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style: AppStyle.txtGilroyMedium16Bluegray900),
CustomTextFormField(
focusNode: FocusNode(),
hintText: "About Me",
controller: aboutMeController,
maxLines: 3,
onChanged: (value) {
aboutMeController.text = value;
},
margin: getMargin(top: 6))
])),
CustomButton(
height: getVerticalSize(50),
text: "Update Profile",
margin: getMargin(top: 24, bottom: 5),
onTap: _updateProfile,
),
],
),
),
SizedBox(height: 20),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResetPasswordScreen(
userData: widget.userData,
userEmail: emailController.text,
), //go to get all entity
),
);
},
child: RichText(
text: TextSpan(
children: <TextSpan>[
TextSpan(
text:
"Password:Change Password for your account Change password",
style: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.blue,
),
),
],
),
),
),
SizedBox(height: 20),
GestureDetector(
onTap: () {
print("change password");
},
child: RichText(
text: TextSpan(
children: <TextSpan>[
TextSpan(
text:
'Security:Logout of all sessions except this current browser Logout other sessions',
style: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.blue,
),
),
],
),
),
),
SizedBox(height: 20),
GestureDetector(
onTap: () {
_logoutUser();
},
child: RichText(
text: TextSpan(
children: <TextSpan>[
TextSpan(
text:
'Deactivation:Remove access to all organizations and workspace in cloudnsure Deactivate account',
style: TextStyle(
fontWeight: FontWeight.normal,
color: Colors.blue,
),
),
],
),
),
),
SizedBox(height: 20),
],
),
),
);
}
}
@@ -0,0 +1,46 @@
import 'package:flutter/material.dart';
import '../../Utils/image_constant.dart';
import '../../Utils/size_utils.dart';
import '../../theme/app_style.dart';
import '../../widgets/app_bar/appbar_image.dart';
import '../../widgets/app_bar/appbar_title.dart';
import '../../widgets/app_bar/custom_app_bar.dart';
class AboutScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
height: getVerticalSize(49),
leadingWidth: 40,
leading: AppbarImage(
height: getSize(24),
width: getSize(24),
svgPath: ImageConstant.imgArrowleftBlueGray900,
margin: getMargin(left: 16, top: 12, bottom: 13),
onTap: () {
Navigator.pop(context);
}),
centerTitle: true,
title: AppbarTitle(text: "About Us")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'About Us',
style: AppStyle.txtGilroyBold18Bluegray900,
),
const SizedBox(height: 20),
Text(
'Create a new project if you have access, if you don\'t have access, then contact the admin.',
textAlign: TextAlign.center,
style: AppStyle.txtGilroyBold16BlueA700,
),
],
),
),
);
}
}
@@ -0,0 +1,57 @@
import 'dart:typed_data';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';
import 'package:dio/dio.dart';
import '../../resources/api_constants.dart';
class ApiServiceProfileManagement {
final String baseUrl = ApiConstants.baseUrl;
final Dio dio = Dio();
Future<void> createFile(
Uint8List fileBytes, String fileName, String token) async {
try {
String apiUrl = "$baseUrl/api/upload";
final mimeType = 'image/jpeg'; // You can set the appropriate MIME type
FormData formData = FormData.fromMap({
'imageFile': MultipartFile.fromBytes(
fileBytes,
filename: fileName,
contentType: MediaType.parse(mimeType),
),
});
Dio dio = Dio(); // Create a new Dio instance
dio.options.headers['Authorization'] = 'Bearer $token';
final response = await dio.post(apiUrl, data: formData);
if (response.statusCode == 200) {
// Handle successful response
print('File uploaded successfully');
} else {
print('Failed to upload file with status: ${response.statusCode}');
}
} catch (error) {
print('Error occurred during form submission: $error');
}
}
String lookupMimeType(String filePath) {
final ext = filePath.split('.').last;
switch (ext) {
case 'jpg':
case 'jpeg':
return 'image/jpeg';
case 'png':
return 'image/png';
case 'pdf':
return 'application/pdf';
// Add more cases for other file types as needed
default:
return 'application/octet-stream'; // Default MIME type
}
}
}
@@ -0,0 +1,318 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import '../../Utils/image_constant.dart';
import '../../Utils/size_utils.dart';
import '../../providers/token_manager.dart';
import '../../resources/api_constants.dart';
import 'package:http/http.dart' as http;
import '../../theme/app_style.dart';
import '../../widgets/app_bar/appbar_image.dart';
import '../../widgets/app_bar/appbar_title.dart';
import '../../widgets/app_bar/custom_app_bar.dart';
import '../../widgets/custom_button.dart';
import '../../widgets/custom_text_form_field.dart';
import '../Login Screen/login_screen.dart';
import '../LogoutService/Logoutservice.dart';
class ResetPasswordScreen extends StatelessWidget {
final String userEmail;
final Map<String, dynamic> userData;
ResetPasswordScreen({required this.userEmail,required this.userData});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar:
CustomAppBar(
height: getVerticalSize(49),
leadingWidth: 40,
leading: AppbarImage(
height: getSize(24),
width: getSize(24),
svgPath: ImageConstant.imgArrowleftBlueGray900,
margin: getMargin(left: 16, top: 12, bottom: 13),
onTap: () {
Navigator.pop(context);
}),
centerTitle: true,
title: AppbarTitle(text: "Reset Password")),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
"You're signed in as $userEmail",
style: AppStyle.txtGilroyMedium16Bluegray800
),
const SizedBox(height: 20),
ResetPasswordForm(userData: userData,userEmail: userEmail),
const SizedBox(height: 20),
GestureDetector(
onTap: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => const LoginScreen()),
(route) => false, // Remove all routes from the stack
);
},
child: Text(
'Wrong account? Log in instead.',
style: AppStyle.txtGreenSemiBold16,
),
),
],
),
),
);
}
}
class ResetPasswordForm extends StatefulWidget {
final String userEmail;
final Map<String, dynamic> userData;
const ResetPasswordForm({super.key, required this.userEmail,required this.userData});
@override
_ResetPasswordFormState createState() => _ResetPasswordFormState();
}
class _ResetPasswordFormState extends State<ResetPasswordForm> {
final TextEditingController oldPasswordController = TextEditingController();
final TextEditingController newPasswordController = TextEditingController();
final TextEditingController reEnterNewPasswordController =
TextEditingController();
var responseMessage;
var isVisible=false;
bool issuccess = false;
bool isOldPasswordVisible = false;
bool isNewPasswordVisible = false;
bool isReEnterNewPasswordVisible = false;
bool _isPasswordValid1 = true;
void _validatePassword1(String password) {
setState(() {
_isPasswordValid1 = password.isNotEmpty;
});
}
bool _isPasswordValid2 = true;
void _validatePassword2(String password) {
setState(() {
_isPasswordValid2 = password.isNotEmpty;
});
}
bool _isPasswordValid3 = true;
void _validatePassword3(String password) {
setState(() {
_isPasswordValid3 = password.isNotEmpty&&password==newPasswordController.text;
});
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
isVisible?Text(responseMessage,style: TextStyle(
color: issuccess?Colors.green:Colors.red, // Set the text color to red
)):const Text(''),
Padding(
padding: getPadding(top: 19),
child: Text("Enter Old Password",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style:
AppStyle.txtGilroyMedium16Bluegray900)),
CustomTextFormField(
focusNode: FocusNode(),
controller: oldPasswordController,
hintText: "Enter Old Password",
margin: getMargin(top: 6),
errorText:
_isPasswordValid1 ? null : 'Please enter your old password',
padding: TextFormFieldPadding.PaddingT12,
textInputAction: TextInputAction.done,
onChanged: _validatePassword1,
validator: (value) {
if (value!.isEmpty) {
return 'Please enter your old password';
}
return null; // Return null to indicate no error
},
textInputType:TextInputType.visiblePassword,
suffix: IconButton(
icon: Icon(
isOldPasswordVisible ? Icons.visibility : Icons.visibility_off,
),
onPressed: () {
setState(() {
isOldPasswordVisible = !isOldPasswordVisible;
});
},
),
suffixConstraints: BoxConstraints(
maxHeight: getVerticalSize(44)),
isObscureText: !isOldPasswordVisible),
Padding(
padding: getPadding(top: 19),
child: Text("Enter New Password",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style:
AppStyle.txtGilroyMedium16Bluegray900)),
CustomTextFormField(
focusNode: FocusNode(),
controller: newPasswordController,
hintText: "Enter New Password",
margin: getMargin(top: 6),
padding: TextFormFieldPadding.PaddingT12,
textInputAction: TextInputAction.done,
suffix: IconButton(
icon: Icon(
isNewPasswordVisible ? Icons.visibility : Icons.visibility_off,
),
onPressed: () {
setState(() {
isNewPasswordVisible = !isNewPasswordVisible;
});
},
),
errorText:
_isPasswordValid2 ? null : 'Please enter your new password',
onChanged: _validatePassword2,
validator: (value) {
if (value!.isEmpty) {
return 'Please enter your new password';
}
return null;
},
suffixConstraints: BoxConstraints(
maxHeight: getVerticalSize(44)),
isObscureText:!isNewPasswordVisible,),
Padding(
padding: getPadding(top: 19),
child: Text("Re-Enter New Password",
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.left,
style:
AppStyle.txtGilroyMedium16Bluegray900)),
CustomTextFormField(
focusNode: FocusNode(),
controller: reEnterNewPasswordController,
hintText: "Re-Enter New Password",
margin: getMargin(top: 6),
padding: TextFormFieldPadding.PaddingT12,
onChanged: _validatePassword3,
validator: (value) {
if (value!.isEmpty) {
return 'Please re-enter your new password';
}
if (value != newPasswordController.text) {
return 'Passwords do not match';
}
return null;
},
suffix: IconButton(
icon: Icon(
isReEnterNewPasswordVisible
? Icons.visibility
: Icons.visibility_off,
),
onPressed: () {
setState(() {
isReEnterNewPasswordVisible = !isReEnterNewPasswordVisible;
});
},
),
errorText:
_isPasswordValid3 ? null : 'Please re-enter your new password',
textInputAction: TextInputAction.done,
suffixConstraints: BoxConstraints(
maxHeight: getVerticalSize(44)),
isObscureText:!isReEnterNewPasswordVisible,),
CustomButton(
height: getVerticalSize(50),
text: "Continue",
margin: getMargin(top: 24, bottom: 5),
onTap: () async {
if (oldPasswordController.text.isEmpty ||
newPasswordController.text.isEmpty ||
reEnterNewPasswordController.text.isEmpty) {
print(oldPasswordController.text);
print(newPasswordController.text);
print(reEnterNewPasswordController.text);
} else {
Map<String, dynamic> passwordData = {
"userId":widget.userData['userId'],
"oldPassword": oldPasswordController.text,
"newPassword": newPasswordController.text,
"confirmPassword": reEnterNewPasswordController.text,
};
final token = await TokenManager.getToken();
final String baseUrl = ApiConstants.baseUrl;
final String apiUrl = '$baseUrl/api/reset_password';
try {
final response = await http.post(Uri.parse(apiUrl),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
body: json.encode(passwordData));
if(response.statusCode==401){
LogoutService.logout();
}
if (response.statusCode <= 209) {
setState(() {
isVisible=true;
issuccess=true;
responseMessage = "Password Changes Successfully";
});
print("success");
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => LoginScreen()),
(route) => false,
);
} else {
setState(() {
isVisible=true;
responseMessage = "Incorrect Password";
});
print(response.statusCode);
}
} catch (e) {
throw Exception('Failed to Update: $e');
}
}
},
),
],
);
}
@override
void dispose() {
oldPasswordController.dispose();
newPasswordController.dispose();
reEnterNewPasswordController.dispose();
super.dispose();
}
}