Adding base project of flutter-hybrid
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user