diff --git a/lib/presentation/Screens/profilepage.dart b/lib/presentation/Screens/profilepage.dart index cb2ca29b..d8dd6e8f 100644 --- a/lib/presentation/Screens/profilepage.dart +++ b/lib/presentation/Screens/profilepage.dart @@ -1,8 +1,87 @@ +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:uae_stat/presentation/components/my_bottom_nav_bar.dart'; +import 'package:intl/intl.dart'; +class ProfileScreen extends StatefulWidget { + @override + State createState() => _ProfileScreenState(); +} + +class _ProfileScreenState extends State { + final _formKey = GlobalKey(); + final TextEditingController _fullNameController = TextEditingController(); + final TextEditingController _dateController = TextEditingController(); + // To keep track of the selected date + DateTime? _selectedDate; + + // Date format for the display + final DateFormat _dateFormat = DateFormat('yyyy-MM-dd'); + final List _countries = [ + 'United Arab Emirates', + 'United States', + 'India', + 'Canada' + ]; + String? _selectedCountry; + bool _termsAccepted = false; + + // Regular expression to validate Full Name (no special characters) + final RegExp _nameRegExp = RegExp(r"^[a-zA-Z\s]+$"); + + // Function to open the date picker + Future _pickDate() async { + final DateTime today = DateTime.now(); + final DateTime initialDate = _selectedDate ?? today.subtract(const Duration(days: 365 * 18)); // Default to 18 years ago + final DateTime firstDate = today.subtract(const Duration(days: 365 * 100)); // Allow picking dates back to 100 years ago + final DateTime lastDate = today; // Allow picking dates up to today + + // Updated Date format to DD/MM/YYYY + final DateFormat _dateFormat = DateFormat('dd/MM/yyyy'); + + final DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: initialDate, + firstDate: firstDate, + lastDate: lastDate, + ); + + if (pickedDate != null && pickedDate != _selectedDate) { + setState(() { + _selectedDate = pickedDate; + _dateController.text = _dateFormat.format(pickedDate); + }); + } + } + + // Function to validate the DOB field + String? _validateDob(String? value) { + if (value == null || value.isEmpty) { + return 'Please select your date of birth'; + } + + final DateTime selectedDate = _selectedDate!; + final DateTime today = DateTime.now(); + + // Check if the selected date is in the future + if (selectedDate.isAfter(today)) { + return 'Date of birth cannot be in the future'; + } + return null; + } + + String? _validateDropdown(String? value) { + if (value == null || value.isEmpty) { + return 'Please select an option'; + } + return null; + } + + void _toggleCheckbox(bool? value) { + setState(() { + _termsAccepted = value ?? false; + }); + } -class ProfileScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( @@ -11,7 +90,9 @@ class ProfileScreen extends StatelessWidget { elevation: 0, leading: IconButton( icon: Icon(Icons.arrow_back_ios_new, color: Colors.black), - onPressed: () {}, + onPressed: () { + print("Back Button"); + }, ), title: Text( 'My Profile', @@ -32,95 +113,259 @@ class ProfileScreen extends StatelessWidget { ], ), body: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - CircleAvatar( - radius: 50, - backgroundImage: AssetImage("assets/edit_profile/profile.png"), // Replace with actual image URL - child: Align( - alignment: Alignment.bottomRight, - child: CircleAvatar( - radius: 15, - backgroundColor: Colors.white, - child: Icon( - Icons.camera_alt, - size: 15, - color: Colors.grey, + child: Form( + key: _formKey, + child: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + children: [ + CircleAvatar( + radius: 50, + backgroundImage: + AssetImage("assets/edit_profile/profile.png"), + // Replace with actual image URL + child: Align( + alignment: Alignment.bottomRight, + child: CircleAvatar( + radius: 15, + backgroundColor: Colors.white, + child: Icon( + Icons.camera_alt, + size: 15, + color: Colors.grey, + ), ), ), ), - ), - SizedBox(height: 20), - ProfileField(label: 'Name', hintText: 'Mohammad Hassan'), - SizedBox(height: 10), - ProfileField(label: 'Email', hintText: 'mohammad.hassan@fcsc.gov.ae'), - SizedBox(height: 10), - ProfileField(label: 'Password', hintText: '********', obscureText: true), - SizedBox(height: 10), - ProfileField(label: 'Date of Birth', hintText: '23/05/1995', isDropdown: true), - SizedBox(height: 10), - ProfileField(label: 'Country/Region', hintText: 'United Arab Emirates', isDropdown: true), - SizedBox(height: 20), - ElevatedButton.icon( - onPressed: () {}, - icon: Icon(Icons.save,color: Colors.white,), - label: Text('Save',style: TextStyle(color: Colors.white),), - style: ElevatedButton.styleFrom( - backgroundColor: Color(0xFF92722A), - minimumSize: Size(double.infinity, 50), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), + SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text("User Name", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + ), + ], + ), + SizedBox(height: 10), + TextFormField( + decoration: InputDecoration( + hintText: 'Mohammad Hassan', + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ),enabled: false, ), ), - ), - ], - ), - ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text("E-mail", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + ), + ], + ), + SizedBox(height: 10), + TextFormField( + decoration: InputDecoration( + hintText: 'mohammad.hassan@fcsc.gov.ae', + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ),enabled: false, + ), + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text("Full Name", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + ), + ], + ), + SizedBox(height: 10), + TextFormField( + enabled: true, + validator: (value) { + if (value == null || value.isEmpty) { + return 'Required'; + } + final nameRegex = RegExp(r"^[a-zA-Z\s]+$"); + if (!nameRegex.hasMatch(value)) { + return 'Invalid Characters'; + } + return null; + }, + controller: _fullNameController, + decoration: InputDecoration( + hintText: "Mohammad", + hintStyle: TextStyle(color: Colors.grey), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text("Date of Birth*", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + ), + ], + ), + SizedBox(height: 10), - ), - //bottomNavigationBar: MyBottomNavBar(), + TextFormField( + controller: _dateController, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + hintText: 'Select your Date of Birth', + suffixIcon: const Icon(Icons.arrow_drop_down_sharp), + ), - ); - } -} + readOnly: true, + onTap: _pickDate, + validator: _validateDob, + ), -class ProfileField extends StatelessWidget { - final String label; - final String hintText; - final bool obscureText; - final bool isDropdown; + SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text("Country/Region*", + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + ), + ], + ), + SizedBox(height: 10), + DropdownButtonFormField( + value: _selectedCountry, + decoration: InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + labelText: 'Select', + ), + items: _countries + .map((item) => DropdownMenuItem( + value: item, + child: Text(item), + )) + .toList(), + onChanged: (String? newValue) { + setState(() { + _selectedCountry = newValue; + }); + }, + validator: _validateDropdown, + ), + SizedBox(height: 20), + Row( + children: [ + Checkbox( + value: _termsAccepted, + onChanged: _toggleCheckbox, + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 10,), + Text.rich( + TextSpan( + text: 'I agree to the ', + style: TextStyle(color: Colors.black), + children: [ + TextSpan( + text: 'Terms & Conditions', + style: TextStyle( + color: Colors.blue, + decoration: TextDecoration.underline, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + // Add action for Terms & Conditions tap + }, + ), + TextSpan( + text: ' and ', + style: TextStyle(color: Colors.black), + ), + TextSpan( + text: 'Privacy Policy', + style: TextStyle( + color: Colors.blue, + decoration: TextDecoration.underline, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + // Add action for Privacy Policy tap + }, + ), + TextSpan( + text: ' of FCSC.', + style: TextStyle(color: Colors.black), + ), + ], + ), + textAlign: TextAlign.start, + maxLines: 2, + overflow: TextOverflow.visible, + softWrap: true, + ), + ], + ), + ), + ], + ), + SizedBox(height: 20), - ProfileField({ - required this.label, - required this.hintText, - this.obscureText = false, - this.isDropdown = false, - }); - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - label, - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), - ), - SizedBox(height: 5), - TextFormField( - obscureText: obscureText, - readOnly: isDropdown, - decoration: InputDecoration( - hintText: hintText, - suffixIcon: isDropdown ? Icon(Icons.arrow_drop_down) : null, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), + Center(child: Text("Change Password",style: TextStyle(color: Colors.blue,decoration: TextDecoration.underline),),), + SizedBox(height: 20), + ElevatedButton.icon( + onPressed: () { + if (_formKey.currentState?.validate() ?? false) { + _formKey.currentState?.save(); + } + }, + icon: Icon( + Icons.save, + color: Colors.white, + ), + label: Text( + 'Save', + style: TextStyle(color: Colors.white), + ), + style: ElevatedButton.styleFrom( + backgroundColor: Color(0xFF92722A), + minimumSize: Size(double.infinity, 50), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + ), + ], ), ), ), - ], + ), + //bottomNavigationBar: MyBottomNavBar(), ); } } + + + + + + + + + + + diff --git a/lib/presentation/components/themed_text_field.dart b/lib/presentation/components/themed_text_field.dart index c1f9ed2b..bc023b2e 100644 --- a/lib/presentation/components/themed_text_field.dart +++ b/lib/presentation/components/themed_text_field.dart @@ -1,3 +1,4 @@ + import 'package:external_repos/external_repos.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; diff --git a/pubspec.lock b/pubspec.lock index d3bf9bc7..2cf3aa30 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -753,6 +753,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" package_config: dependency: transitive description: @@ -857,6 +865,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" pub_semver: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 58bff484..cab28e16 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -51,6 +51,7 @@ dependencies: freezed_annotation: ^2.4.4 shared_preferences: ^2.2.3 flutter_rating_bar: ^4.0.1 + provider: ^6.1.2 dependency_overrides: fading_edge_scrollview: ^4.1.1