import 'dart:io'; import 'package:email_validator/email_validator.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:job_app/config/palette.dart'; import 'package:job_app/models/APiResponse.dart'; import 'package:job_app/models/Country/country_details.dart'; import 'package:job_app/models/Country/state.dart'; import 'package:job_app/services/Auth/update_user_info.dart'; import 'package:job_app/services/countries_service.dart'; import 'package:job_app/singletons/country.dart'; import 'package:job_app/singletons/profile_image.dart'; import 'package:job_app/singletons/user_info.dart'; import 'package:job_app/widgets/profile_image.dart'; import 'package:job_app/widgets/update_profile_image.dart'; import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; class UpdateProfile extends StatefulWidget { const UpdateProfile({Key key}) : super(key: key); @override _UpdateProfileState createState() => _UpdateProfileState(); } class _UpdateProfileState extends State { bool isFirstNameReadOnly = true; FocusNode firstNameFocusNode = new FocusNode(); TextEditingController firstNameController = TextEditingController(); bool firstNameValid = true; bool isLastNameReadOnly = true; FocusNode lastNameFocusNode = new FocusNode(); TextEditingController lastNameController = TextEditingController(); bool lastNameValid = true; bool isEmailReadOnly = true; FocusNode emailFocusNode = new FocusNode(); TextEditingController emailController = TextEditingController(); bool emailValid = true; bool isJobReadOnly = true; FocusNode jobFocusNode = new FocusNode(); TextEditingController jobController = TextEditingController(); bool jobValid = true; bool isPhoneReadOnly = true; FocusNode phoneFocusNode = new FocusNode(); TextEditingController phoneController = TextEditingController(); bool phoneValid = true; bool isCountryReadOnly = true; FocusNode countryFocusNode = new FocusNode(); String countryValue; bool countryValid = true; bool isCityReadOnly = true; FocusNode cityFocusNode = new FocusNode(); String cityValue; bool cityValid = true; GlobalKey _globalKey = GlobalKey(); CountriesService countriesService = CountriesService(); CountryDetailsModel countryDetails; List countryStates = []; String countryText="Country"; String cityText="City"; String cityState="Loading..."; File profileImage; Future getCountries() async { print(countrySingleTons.pageNumber); await countriesService.getCountries( size: 10, page: countrySingleTons.pageNumber); } @override void initState() { // TODO: implement initState super.initState(); firstNameController.text = userInfo.user.firstName; lastNameController.text = userInfo.user.lastName; emailController.text = userInfo.user.email; jobController.text = userInfo.user.jobtitle; phoneController.text = userInfo.user.phonenumber; countryText=userInfo.user.country; cityText=userInfo.user.city; getCountries(); } @override Widget build(BuildContext context) { return GestureDetector( onTap: () { FocusScope.of(context).requestFocus(new FocusNode()); setState(() { isFirstNameReadOnly = true; isLastNameReadOnly = true; isEmailReadOnly = true; isJobReadOnly = true; }); }, child: Scaffold( backgroundColor: Palette.backgroundColor, body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.fromLTRB(10, 40, 25, 0), child: ChangeNotifierProvider.value( value: ProfileImage(), child: Consumer( builder: (context,data,child) { profileImage=data.image; return Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ IconButton( highlightColor: Colors.transparent, focusColor: Colors.transparent, splashColor: Colors.transparent, onPressed: () { Navigator.pop(context); }, icon: SvgPicture.asset( "assets/icons/arrow_left.svg", color: Colors.black, ), ), Container( decoration: BoxDecoration( color: Palette.primary, borderRadius: BorderRadius.circular(100)), child: IconButton( highlightColor: Colors.transparent, focusColor: Colors.transparent, splashColor: Colors.transparent, onPressed: () async{ UpdateUserInfo updateUser =UpdateUserInfo(); if (_globalKey.currentState.validate()) { ApiResponseModel response = await updateUser.updateInfos( file: profileImage, firstName: firstNameController.text, lastName: lastNameController.text, phoneNumber: phoneController.text, jobTitle: jobController.text, email: emailController.text, city: cityText, country: countryText ); } }, icon: SvgPicture.asset("assets/icons/validate.svg"), ), ), ], ), SizedBox( height: 40, ), Column( children: [ CircleAvatar( radius: 55, backgroundColor: Colors.grey, foregroundImage: data.image==null?NetworkImage( "https://server.thejob.net/" + userInfo.user.image.url):FileImage(data.image), ), SizedBox( height: 10, ), ElevatedButton(onPressed: (){ data.clearPhoto(); }, child: Text("'Reset photo'")), TextButton( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (states) => Palette.primary), overlayColor: MaterialStateProperty.resolveWith( (states) => Colors.transparent)), onPressed: (){ updateProfilePicture(context); }, child: Text( "Update photo", style: TextStyle( fontFamily: "MontserratRegular", fontSize: 16, color: Colors.white), )), SizedBox( height: 40, ), Form( key: _globalKey, child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ keyText("First name"), textField( focusNode: firstNameFocusNode, isReadOnly: isFirstNameReadOnly, editingController: firstNameController, value: "first name"), ], ), SizedBox( height: 40, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ keyText("Last name"), textField( focusNode: lastNameFocusNode, isReadOnly: isLastNameReadOnly, editingController: lastNameController, value: "last name"), ], ), SizedBox( height: 40, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ keyText("Job title"), textField( focusNode: jobFocusNode, isReadOnly: isJobReadOnly, editingController: jobController, value: "job title"), ], ), SizedBox( height: 40, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ keyText("Email"), textField( focusNode: emailFocusNode, isReadOnly: isEmailReadOnly, editingController: emailController, value: "email"), ], ), SizedBox( height: 40, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ keyText("Phone number"), textField( focusNode: phoneFocusNode, isReadOnly: isPhoneReadOnly, editingController: phoneController, value: "phone number"), ], ), SizedBox( height: 40, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ keyText("Country"), countryDropdownField(), ], ), SizedBox( height: 40, ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ keyText("City"), cityDropdownField(), ], ), SizedBox( height: 120, ), ], ), ), ], ) ], ); } ), ), ), ), ), ); } Widget keyText(String text) { return Padding( padding: const EdgeInsets.only(left: 20), child: Container( child: Text( text, style: TextStyle( fontFamily: 'MontserratMedium', fontWeight: FontWeight.bold, color: Colors.grey, fontSize: text == "Phone number" ? 14 : 16, letterSpacing: text == "Phone number" ? 0 : 1), ), ), ); } Widget textField( {FocusNode focusNode, bool isReadOnly, TextEditingController editingController, String value}) { return Container( width: 180, height: 40, child: TextFormField( validator: (val) { if (value == "first name") { if (val.isEmpty || val.length < 2) { return "First name is short"; } } if (value == "last name") { if (val.isEmpty || val.length < 2) { return "Last name is short"; } } if (value == "email") { if (val.isEmpty) { return "email is required"; } else if (!EmailValidator.validate(val)) { return "Email is not valid"; } } if (value == "job title") { if (val.isEmpty || val.length < 1) { return "Job title is short"; } } if (value == "phone number") { if (val.isEmpty || val.length < 6) { return "Phone number is short"; } else if (int.tryParse(val) == null) { return "Field must contain only digits"; } } return null; }, focusNode: focusNode, readOnly: isReadOnly, controller: editingController, autocorrect: false, cursorColor: Palette.primary, scrollPhysics: BouncingScrollPhysics(), textAlignVertical: TextAlignVertical.center, style: TextStyle( fontFamily: 'MontserratRegular', fontSize: 16, color: Colors.black.withOpacity(0.6)), decoration: InputDecoration( focusColor: Palette.primary, fillColor: Palette.primary, hoverColor: Palette.primary, contentPadding: EdgeInsets.fromLTRB(5, 0, 0, 5), suffixIcon: Container( margin: EdgeInsets.fromLTRB(0, 0, 0, 0), child: TextButton( onPressed: () { setState(() { if (value == "first name") { setState(() { isFirstNameReadOnly = false; }); } else if (value == "last name") { setState(() { isLastNameReadOnly = false; }); } else if (value == "email") { setState(() { isEmailReadOnly = false; }); } else if (value == "job title") { setState(() { isJobReadOnly = false; }); } else if (value == "phone number") { setState(() { isPhoneReadOnly = false; }); } }); if(firstNameController.text.isEmpty || firstNameController.text.length<2){ setState(() { firstNameController.text=userInfo.user.firstName; }); } FocusScope.of(context).requestFocus(focusNode); }, child: SvgPicture.asset("assets/icons/editing.svg")), ), enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey, width: 0.5), ), focusedBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.grey, width: 0.5), ), errorBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.red, width: 0.5), ), focusedErrorBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.red, width: 0.5), ), errorStyle: TextStyle( height: 1, fontSize: 10, fontFamily: 'MontserratExtraLight', fontWeight: FontWeight.bold, letterSpacing: 1)), ), ); } Widget countryDropdownField() { return ChangeNotifierProvider.value( value: CountrySingleTons(), child: Container( width: 180, height: 40, padding: EdgeInsets.only(left: 5, right: 22, top: 6), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.black, width: 0.2))), child: PopupMenuButton( offset: Offset(35, 35), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible( child: Text( "$countryText", style: TextStyle( fontFamily: 'MontserratRegular', fontSize: 16, color: Colors.black.withOpacity(0.6)), ), ), Icon( Icons.keyboard_arrow_down_rounded, color: Palette.hintText, size: 18, ) ], ), itemBuilder: (context) => [ PopupMenuItem( enabled: false, child: Container( width: 120, height: 180, child: ChangeNotifierProvider.value( value: CountrySingleTons(), child: Consumer( builder: (context, data, child) { return data.countries.isNotEmpty ? ListView.builder( itemCount: data.countries.length, shrinkWrap: true, physics: BouncingScrollPhysics(), itemBuilder: (context, index) => Padding( padding: const EdgeInsets.all(8.0), child: GestureDetector( onTap: () async { Navigator.pop(context); setState(() { countryText=data.countries[index].name; cityText="City"; cityState="Loading..."; }); countryStates.clear(); ApiResponseModel response = await countriesService.getCountryById( data.countries[index].id); countryDetails = response.data; setState(() { if(countryDetails.states.isEmpty){ cityState="No city has been found"; } countryStates = countryDetails.states; }); }, child: Text( data.countries[index].name, style: TextStyle( fontFamily: 'MontserratRegular', fontSize: 16, color: Colors.black.withOpacity(0.6)), ), ), ), ) : Text("Loading", style: TextStyle( fontFamily: 'MontserratRegular', fontSize: 16, color: Colors.black.withOpacity(0.6)), ); }, ), ), ), ), ], ), ), ); } Widget cityDropdownField() { return Container( width: 180, height: 40, padding: EdgeInsets.only(left: 5, right: 22, top: 6), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.black, width: 0.2))), child: PopupMenuButton( offset: Offset(35, 35), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Flexible( child: Text( "$cityText", style: TextStyle( fontFamily: 'MontserratRegular', fontSize: 16, color: Colors.black.withOpacity(0.6)), ), ), Icon( Icons.keyboard_arrow_down_rounded, color: Palette.hintText, size: 18, ) ], ), itemBuilder: (context) => [ PopupMenuItem( enabled: false, child: Container( width: 120, height: 180, child: ChangeNotifierProvider.value( value: CountrySingleTons(), child: Consumer( builder: (context,data,child) { return data.countryDetails.states.isNotEmpty?ListView.builder( itemCount: data.countryDetails.states.length, itemBuilder: (context,i)=>Padding( padding: const EdgeInsets.all(8.0), child: GestureDetector( onTap: (){ Navigator.pop(context); setState(() { cityText=data.countryDetails.states[i].name; }); }, child: Text( data.countryDetails.states[i].name, style: TextStyle( fontFamily: 'MontserratRegular', fontSize: 16, color: Colors.black.withOpacity(0.6)), ), ), ), ):Text("$cityState", style: TextStyle( fontFamily: 'MontserratRegular', fontSize: 16, color: Colors.black.withOpacity(0.6)),); } ), ), ), ) ] )); } }