525 lines
19 KiB
Dart
525 lines
19 KiB
Dart
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),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|