0% found this document useful (0 votes)
3 views

Profile

The document is a Flutter widget for a profile completion screen that allows users to input personal information and upload images. It includes fields for name, phone number, property type, city, area, preferred living type, and budget, along with options to upload ID images and a profile picture. The screen handles user authentication, image uploading to Firebase, and saving the profile data to Firestore, with navigation to the next screen upon completion.

Uploaded by

mostafa morsy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Profile

The document is a Flutter widget for a profile completion screen that allows users to input personal information and upload images. It includes fields for name, phone number, property type, city, area, preferred living type, and budget, along with options to upload ID images and a profile picture. The screen handles user authentication, image uploading to Firebase, and saving the profile data to Firestore, with navigation to the next screen upon completion.

Uploaded by

mostafa morsy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 9

import 'package:cloud_firestore/cloud_firestore.

dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import '../services/auth_service.dart';
import 'upload_id_screen.dart';

class ProfileCompletionScreen extends StatefulWidget {


const ProfileCompletionScreen({super.key});

@override
_ProfileCompletionScreenState createState() => _ProfileCompletionScreenState();
}

class _ProfileCompletionScreenState extends State<ProfileCompletionScreen> {


String? _selectedPropertyType;
String? _selectedCity;
String? _selectedArea;
String? _preferredLivingType;
final _budgetController = TextEditingController();
final _nameController = TextEditingController();
final _phoneController = TextEditingController();
File? _profileImage;
bool _isLoading = false;
String _errorMessage = '';
bool _idImagesUploaded = false;
Map<String, File?> _idImages = {};

final List<String> _propertyTypes = [


'Apartment',
'Villa',
'Studio',
'Chalet',
'Duplex'
];
final List<String> _cities = ['Cairo', 'Giza'];

final Map<String, List<String>> _areas = {


'Cairo': [
'10th of Ramadan',
'5th Settlement',
'Ain Sokhna',
'Downtown',
'Heliopolis',
'Katameya',
'Maadi',
'Madinaty',
'Nasr City',
'New Cairo',
'New Capital',
'Obour',
'Rehab',
'Shorouk',
'Tagamoa',
'Zamalek',
]..sort(),
'Giza': [
'6th October',
'Agouza',
'Badrashin',
'Dokki',
'El Haram',
'Faisal',
'Hadayek October',
'Haram City',
'Imbaba',
'Mohandessin',
'Pyramids',
'Sheikh Zayed',
'Zayed City',
]..sort(),
};

List<String> get _availableAreas {


return _selectedCity != null ? _areas[_selectedCity]! : [];
}

Future<void> _pickProfileImage() async {


final pickedFile = await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedFile != null) {
setState(() {
_profileImage = File(pickedFile.path);
});
}
}

Future<String?> _uploadImageToStorage(File? image, String path) async {


if (image == null) return null;
try {
final storageRef = FirebaseStorage.instance.ref().child(path);
final uploadTask = await storageRef.putFile(image);
return await uploadTask.ref.getDownloadURL();
} catch (e) {
print('Image upload error: $e');
throw Exception('Failed to upload image: $e');
}
}

Future<void> _saveProfileAndContinue() async {


setState(() {
_isLoading = true;
_errorMessage = '';
});

try {
User? user = FirebaseAuth.instance.currentUser;

if (user != null) {
String? profileImageUrl;
if (_profileImage != null) {
profileImageUrl = await _uploadImageToStorage(
_profileImage,
'users/${user.uid}/profile_image.jpg',
);
}
String? frontIDImageUrl;
String? backIDImageUrl;
if (_idImages['frontID'] != null) {
frontIDImageUrl = await _uploadImageToStorage(
_idImages['frontID'],
'users/${user.uid}/front_id_image.jpg',
);
}
if (_idImages['backID'] != null) {
backIDImageUrl = await _uploadImageToStorage(
_idImages['backID'],
'users/${user.uid}/back_id_image.jpg',
);
}

await FirebaseFirestore.instance.collection('users').doc(user.uid).set({
'name': _nameController.text,
'phone': _phoneController.text,
'propertyType': _selectedPropertyType,
'city': _selectedCity,
'area': _selectedArea,
'preferredLivingType': _preferredLivingType,
'budget': _budgetController.text,
'profileImage': profileImageUrl,
'frontIDImage': frontIDImageUrl,
'backIDImage': backIDImageUrl,
});

if (mounted) {
Navigator.pushReplacementNamed(context, '/suggest-action');
}
} else {
setState(() {
_isLoading = false;
_errorMessage = 'User not authenticated';
});
}
} catch (e) {
setState(() {
_isLoading = false;
_errorMessage = 'Failed to save profile data: $e';
});
}
}

void _skipAndContinue() {
if (mounted) {
Navigator.pushReplacementNamed(context, '/suggest-action');
}
}

Future<void> _uploadIDImages() async {


final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const IDUploadScreen()),
);

if (result != null && result is Map<String, File?>) {


setState(() {
_idImages = result;
_idImagesUploaded = _idImages['frontID'] != null && _idImages['backID'] !=
null;
print('ID Images Uploaded: $_idImagesUploaded, Front: $
{_idImages['frontID']}, Back: ${_idImages['backID']}');
});
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[200],
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Card(
elevation: 8,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Complete Your Profile',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.black,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
const Text(
'Help us personalize your experience by answering a few quick
questions.',
style: TextStyle(
fontSize: 16,
color: Colors.grey,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 30),
// Profile Image
GestureDetector(
onTap: _pickProfileImage,
child: CircleAvatar(
radius: 50,
backgroundImage: _profileImage != null ?
FileImage(_profileImage!) : null,
child: _profileImage == null ? const Icon(Icons.camera_alt,
size: 40) : null,
),
),
const SizedBox(height: 20),
// Name
TextField(
controller: _nameController,
decoration: InputDecoration(
labelText: 'Your Name',
prefixIcon: const Icon(Icons.person),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
),
),
const SizedBox(height: 20),
// Phone Number
TextField(
controller: _phoneController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: 'Phone Number',
prefixIcon: const Icon(Icons.phone),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
),
),
const SizedBox(height: 20),
// Property Type
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'Preferred Property Type',
prefixIcon: const Icon(Icons.home_outlined),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
),
value: _selectedPropertyType,
hint: const Text('Select property type'),
items: _propertyTypes.map((String type) {
return DropdownMenuItem<String>(
value: type,
child: Text(type),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
_selectedPropertyType = newValue;
});
},
),
const SizedBox(height: 20),
// City
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'City',
prefixIcon: const Icon(Icons.location_city),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
),
value: _selectedCity,
hint: const Text('Select city'),
items: _cities.map((String city) {
return DropdownMenuItem<String>(
value: city,
child: Text(city),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
_selectedCity = newValue;
_selectedArea = null; // Reset area when city changes
});
},
),
const SizedBox(height: 20),
// Area
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'Area',
prefixIcon: const Icon(Icons.place),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
),
value: _selectedArea,
hint: const Text('Select area'),
items: _selectedCity != null
? _availableAreas.map((String area) {
return DropdownMenuItem<String>(
value: area,
child: Text(area),
);
}).toList()
: [],
onChanged: _selectedCity != null
? (String? newValue) {
setState(() {
_selectedArea = newValue;
});
}
: null,
),
const SizedBox(height: 20),
// Preferred Living Type
DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: 'Preferred Living Type',
prefixIcon: const Icon(Icons.home),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
),
value: _preferredLivingType,
hint: const Text('Select living type'),
items: ['Investment', 'Family'].map((String type) {
return DropdownMenuItem<String>(
value: type,
child: Text(type),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
_preferredLivingType = newValue;
});
},
),
const SizedBox(height: 20),
// Budget
TextField(
controller: _budgetController,
keyboardType: const TextInputType.numberWithOptions(decimal:
true),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d*'))
],
decoration: InputDecoration(
labelText: 'Your Budget (EGP)',
prefixIcon: const Icon(Icons.attach_money),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
),
),
),
const SizedBox(height: 30),

// ‫الجزء الجديد بتاع رفع البطاقة‬


GestureDetector(
onTap: _uploadIDImages,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.grey[100],
border: Border.all(
color: Colors.grey[400]!,
),
),
padding: const EdgeInsets.all(16),
child: Row(
children: [
const Icon(Icons.credit_card),
const SizedBox(width: 16),
Expanded(
child: Text(
_idImagesUploaded
? 'ID Images Uploaded Successfully'
: 'Upload Your ID Images',
style: TextStyle(
fontSize: 16,
color: _idImagesUploaded ? Colors.green :
Colors.black87,
),
),
),
const Icon(Icons.arrow_forward_ios),
],
),
),
),
const SizedBox(height: 30),

if (_errorMessage.isNotEmpty)
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: Text(
_errorMessage,
style: const TextStyle(color: Colors.red, fontSize: 14),
textAlign: TextAlign.center,
),
),
// Save and Continue Button (‫)وظيفته دلوقتي الحفظ بس‬
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _isLoading ? null : _saveProfileAndContinue,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.black,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
child: _isLoading
? const CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Save and Continue',
style: TextStyle(
fontSize: 18,
color: Colors.white,
),
),
),
),
const SizedBox(height: 15),
// Skip for Now Link
GestureDetector(
onTap: _isLoading ? null : _skipAndContinue,
child: const Text(
'Skip for Now',
style: TextStyle(
fontSize: 16,
color: Colors.blue,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
),
),
),
);
}

@override
void dispose() {
_budgetController.dispose();
_nameController.dispose();
_phoneController.dispose();
super.dispose();
}
}

You might also like