feat: Implement the home screen with new UI components and assets, and refine authentication screens and routing.
This commit is contained in:
129
lib/features/home/presentation/widgets/features_section.dart
Normal file
129
lib/features/home/presentation/widgets/features_section.dart
Normal file
@@ -0,0 +1,129 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||
|
||||
class FeaturesSection extends StatelessWidget {
|
||||
const FeaturesSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
'Find Trusted Real Estate Professionals On Demand',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'Quickly connect with the right agents exactly when you need them.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
_buildFeatureCard(
|
||||
icon: 'assets/icons/hire_quickly_icon.svg',
|
||||
fallbackIcon: Icons.bolt,
|
||||
title: 'Hire Quickly',
|
||||
description:
|
||||
'Connect with experienced local real estate agents who match your needs and preferences. Our simple process helps you get started quickly and move forward without delays or unnecessary complexity.',
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildFeatureCard(
|
||||
icon: 'assets/icons/verified_icon.svg',
|
||||
fallbackIcon: Icons.verified_user_outlined,
|
||||
title: 'Verified Agents',
|
||||
description:
|
||||
'All agents are carefully identity-verified and background-checked to ensure trust and safety. You can confidently work with professionals who meet quality and reliability standards.',
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildFeatureCard(
|
||||
icon: 'assets/icons/top_rated_icon.svg',
|
||||
fallbackIcon: Icons.star_outline,
|
||||
title: 'Top Rated',
|
||||
description:
|
||||
'Work with highly rated agents known for strong expertise and positive client feedback. Their consistent performance helps you make informed and confident property decisions.',
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildFeatureCard(
|
||||
icon: 'assets/icons/trusted_icon.svg',
|
||||
fallbackIcon: Icons.people_outline,
|
||||
title: 'Trusted by Thousands',
|
||||
description:
|
||||
'Thousands of buyers, sellers, and renters trust our platform to connect with reliable, verified agents. Our experienced professionals support every step of the property journey, helping users make confident decisions with clarity, trust, and ease.',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildFeatureCard({
|
||||
required String icon,
|
||||
required IconData fallbackIcon,
|
||||
required String title,
|
||||
required String description,
|
||||
}) {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(
|
||||
color: AppColors.primaryDark,
|
||||
width: 0.1,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
icon,
|
||||
width: 35,
|
||||
height: 35,
|
||||
placeholderBuilder: (_) => Icon(
|
||||
fallbackIcon,
|
||||
size: 35,
|
||||
color: AppColors.accentOrange,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
description,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
136
lib/features/home/presentation/widgets/hero_section.dart
Normal file
136
lib/features/home/presentation/widgets/hero_section.dart
Normal file
@@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||
|
||||
class HeroSection extends StatelessWidget {
|
||||
const HeroSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
// Background image
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
child: Image.asset(
|
||||
'assets/images/hero_bg.png',
|
||||
width: double.infinity,
|
||||
height: 580,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
// Content overlay
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 40),
|
||||
const Text(
|
||||
'Discover verified, top-rated real estate professionals.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
height: 1.1,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
// Search Agents Card
|
||||
_buildSearchCard(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchCard() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.accentOrange,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Center(
|
||||
child: Text(
|
||||
'Search Agents',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildSearchField('Types'),
|
||||
const SizedBox(height: 12),
|
||||
_buildSearchField('Name or Keyword'),
|
||||
const SizedBox(height: 12),
|
||||
_buildSearchField('Location'),
|
||||
const SizedBox(height: 12),
|
||||
_buildSearchField('Categories'),
|
||||
const SizedBox(height: 12),
|
||||
// See All Agents button
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.primaryDark,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'See All Agents',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchField(String hint) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
hint,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (hint == 'Types' || hint == 'Categories')
|
||||
const Icon(
|
||||
Icons.keyboard_arrow_down,
|
||||
color: AppColors.primaryDark,
|
||||
size: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
262
lib/features/home/presentation/widgets/home_header.dart
Normal file
262
lib/features/home/presentation/widgets/home_header.dart
Normal file
@@ -0,0 +1,262 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||
import 'package:real_estate_mobile/features/auth/presentation/providers/auth_provider.dart';
|
||||
|
||||
class HomeHeader extends StatelessWidget {
|
||||
const HomeHeader({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 23, vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF648188),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Logo
|
||||
Image.asset(
|
||||
'assets/icons/logo.png',
|
||||
width: 109,
|
||||
height: 29,
|
||||
),
|
||||
// Right side: notification + hamburger menu
|
||||
Row(
|
||||
children: [
|
||||
// Notification bell
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: const Icon(
|
||||
Icons.notifications_outlined,
|
||||
color: AppColors.primaryDark,
|
||||
size: 26,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
// Hamburger menu
|
||||
GestureDetector(
|
||||
onTap: () => _openDrawer(context),
|
||||
child: const Icon(
|
||||
Icons.menu,
|
||||
color: AppColors.primaryDark,
|
||||
size: 26,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openDrawer(BuildContext context) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: Colors.transparent,
|
||||
builder: (context) => const _MenuDrawer(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MenuDrawer extends ConsumerWidget {
|
||||
const _MenuDrawer();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return DraggableScrollableSheet(
|
||||
initialChildSize: 0.85,
|
||||
minChildSize: 0.5,
|
||||
maxChildSize: 0.95,
|
||||
builder: (context, scrollController) {
|
||||
return Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Handle bar
|
||||
const SizedBox(height: 12),
|
||||
Container(
|
||||
width: 40,
|
||||
height: 4,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.divider,
|
||||
borderRadius: BorderRadius.circular(2),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Header with logo and close
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/icons/logo.png',
|
||||
width: 109,
|
||||
height: 29,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.inputFill,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
color: AppColors.primaryDark,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const Divider(color: AppColors.divider, height: 1),
|
||||
// Menu items
|
||||
Expanded(
|
||||
child: ListView(
|
||||
controller: scrollController,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8),
|
||||
children: [
|
||||
_buildMenuItem(
|
||||
context,
|
||||
icon: Icons.home_outlined,
|
||||
label: 'Home',
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
context.go('/home');
|
||||
},
|
||||
),
|
||||
_buildMenuItem(
|
||||
context,
|
||||
icon: Icons.school_outlined,
|
||||
label: 'Education',
|
||||
onTap: () => Navigator.pop(context),
|
||||
),
|
||||
_buildMenuItem(
|
||||
context,
|
||||
icon: Icons.info_outline,
|
||||
label: 'About Us',
|
||||
onTap: () => Navigator.pop(context),
|
||||
),
|
||||
_buildMenuItem(
|
||||
context,
|
||||
icon: Icons.help_outline,
|
||||
label: "FAQ's",
|
||||
onTap: () => Navigator.pop(context),
|
||||
),
|
||||
_buildMenuItem(
|
||||
context,
|
||||
icon: Icons.mail_outline,
|
||||
label: 'Contact',
|
||||
onTap: () => Navigator.pop(context),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(color: AppColors.divider, height: 1),
|
||||
const SizedBox(height: 16),
|
||||
_buildMenuItem(
|
||||
context,
|
||||
icon: Icons.person_outline,
|
||||
label: 'Account Settings',
|
||||
onTap: () => Navigator.pop(context),
|
||||
),
|
||||
_buildMenuItem(
|
||||
context,
|
||||
icon: Icons.notifications_outlined,
|
||||
label: 'Notification Settings',
|
||||
onTap: () => Navigator.pop(context),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(color: AppColors.divider, height: 1),
|
||||
const SizedBox(height: 24),
|
||||
// Log Out button
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: OutlinedButton.icon(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
ref.read(authProvider.notifier).logout();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.logout,
|
||||
color: AppColors.accentOrange,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text(
|
||||
'Log Out',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.accentOrange,
|
||||
),
|
||||
),
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||
side: const BorderSide(
|
||||
color: AppColors.accentOrange,
|
||||
width: 1.5,
|
||||
),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildMenuItem(
|
||||
BuildContext context, {
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, color: AppColors.primaryDark, size: 24),
|
||||
const SizedBox(width: 16),
|
||||
Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
const Icon(
|
||||
Icons.chevron_right,
|
||||
color: AppColors.hintText,
|
||||
size: 22,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
111
lib/features/home/presentation/widgets/testimonials_section.dart
Normal file
111
lib/features/home/presentation/widgets/testimonials_section.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||
|
||||
class TestimonialsSection extends StatelessWidget {
|
||||
const TestimonialsSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
// Testimonial card
|
||||
SizedBox(
|
||||
height: 380,
|
||||
child: ListView.builder(
|
||||
scrollDirection: Axis.horizontal,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
itemCount: 3,
|
||||
itemBuilder: (context, index) => Padding(
|
||||
padding: const EdgeInsets.only(right: 16),
|
||||
child: _buildTestimonialCard(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTestimonialCard() {
|
||||
return Container(
|
||||
width: 315,
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primaryDark,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Quote icon
|
||||
const Text(
|
||||
'\u201C',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 48,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.accentOrange,
|
||||
height: 0.8,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'I have been working with Lorem ..',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Sed dignissim, nisl eget tincidunt vulputate, lacus justo bibendum ipsum, vitae tempus risus lorem at nunc.',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
// Stars
|
||||
Row(
|
||||
children: List.generate(
|
||||
5,
|
||||
(index) => const Padding(
|
||||
padding: EdgeInsets.only(right: 4),
|
||||
child: Icon(
|
||||
Icons.star,
|
||||
color: AppColors.accentOrange,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Author info
|
||||
const Text(
|
||||
'Conor Kenney',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const Text(
|
||||
'Chief Operations Officer',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,433 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||
|
||||
class TopProfessionalsSection extends StatelessWidget {
|
||||
const TopProfessionalsSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
'"Meet top real estate professionals"',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Agents / Lenders Tab
|
||||
_buildCategoryTab(),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Agent Card
|
||||
_buildAgentCard(),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Progress indicator
|
||||
_buildProgressIndicator(),
|
||||
const SizedBox(height: 32),
|
||||
|
||||
// See All Agents CTA
|
||||
_buildSeeAllAgentsCta(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCategoryTab() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(color: AppColors.primaryDark, width: 0.1),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// Active tab - Agents
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.accentOrange,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
'assets/icons/agents_tab_icon.svg',
|
||||
width: 24,
|
||||
height: 24,
|
||||
placeholderBuilder: (_) => const Icon(
|
||||
Icons.people,
|
||||
color: Colors.white,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'Agents',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
// Inactive tab - Lenders
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
'assets/icons/lenders_tab_icon.svg',
|
||||
width: 24,
|
||||
height: 24,
|
||||
placeholderBuilder: (_) => const Icon(
|
||||
Icons.calendar_today,
|
||||
color: AppColors.primaryDark,
|
||||
size: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'Lenders',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 17,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAgentCard() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(color: AppColors.primaryDark, width: 0.1),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Agent image
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(15)),
|
||||
child: Image.asset(
|
||||
'assets/images/agent_profile_image.png',
|
||||
width: double.infinity,
|
||||
height: 192,
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __, ___) => Container(
|
||||
width: double.infinity,
|
||||
height: 192,
|
||||
color: AppColors.gradientStart,
|
||||
child: const Icon(Icons.person, size: 60, color: AppColors.primaryDark),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Name and badges row
|
||||
Row(
|
||||
children: [
|
||||
const Text(
|
||||
'Arjun Mehta',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
SvgPicture.asset(
|
||||
'assets/icons/verified_badge_icon.svg',
|
||||
width: 16,
|
||||
height: 16,
|
||||
placeholderBuilder: (_) => const Icon(
|
||||
Icons.verified,
|
||||
color: Colors.blue,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
SvgPicture.asset(
|
||||
'assets/icons/star_rating_icon.svg',
|
||||
width: 16,
|
||||
height: 16,
|
||||
placeholderBuilder: (_) => const Icon(
|
||||
Icons.star,
|
||||
color: AppColors.accentOrange,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Text(
|
||||
'4.9 Rating',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
// Verified and Location
|
||||
const Text(
|
||||
'"Verified local agent"',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Color(0xFF638559),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// Location
|
||||
Row(
|
||||
children: [
|
||||
const Text(
|
||||
'Location:',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
SvgPicture.asset(
|
||||
'assets/icons/location_pin_icon.svg',
|
||||
width: 14,
|
||||
height: 14,
|
||||
placeholderBuilder: (_) => const Icon(
|
||||
Icons.location_on,
|
||||
color: AppColors.accentOrange,
|
||||
size: 14,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Text(
|
||||
'San Francisco, CA',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
// Expertise
|
||||
Row(
|
||||
children: [
|
||||
const Text(
|
||||
'Expertise:',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'(Residential Property Expert)',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Tags
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
_buildTag('Residential'),
|
||||
_buildTag('Rental'),
|
||||
_buildTag('Commercial'),
|
||||
_buildTag('Inspection'),
|
||||
_buildTag('Land'),
|
||||
_buildTag('Rental'),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// Experience
|
||||
RichText(
|
||||
text: const TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: 'Experience: ',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: '10+ years in the real estate industry.',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTag(String label) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(color: AppColors.primaryDark, width: 0.7),
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProgressIndicator() {
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: 5,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(color: AppColors.primaryDark, width: 0.1),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: 5,
|
||||
width: 103,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primaryDark,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSeeAllAgentsCta() {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [AppColors.gradientStart, AppColors.gradientEnd],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(color: AppColors.primaryDark, width: 0.2),
|
||||
boxShadow: const [
|
||||
BoxShadow(
|
||||
color: Color(0xFFD9D9D9),
|
||||
offset: Offset(10, 0),
|
||||
blurRadius: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/icons/network_icon.svg',
|
||||
width: 30,
|
||||
height: 23,
|
||||
errorBuilder: (_, __, ___) => const Icon(
|
||||
Icons.hub,
|
||||
color: AppColors.primaryDark,
|
||||
size: 30,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
'Discover 5,000+ Top Real Estate Agents in Our Network',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.primaryDark,
|
||||
foregroundColor: Colors.white,
|
||||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
child: const Text(
|
||||
'See All Agents',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
140
lib/features/home/presentation/widgets/trust_stats_section.dart
Normal file
140
lib/features/home/presentation/widgets/trust_stats_section.dart
Normal file
@@ -0,0 +1,140 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||
|
||||
class TrustStatsSection extends StatelessWidget {
|
||||
const TrustStatsSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
"Our Clients' Trust Is Our Foundation",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'We help buyers, sellers, and investors close successful real estate deals with confidence in every transaction.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'Clients rate our real estate services 4.9 out of 5 on average, based on recent client reviews.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(color: AppColors.divider),
|
||||
const SizedBox(height: 16),
|
||||
// Stats row
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Cities stat
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
RichText(
|
||||
text: const TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '25+ Cities &\n',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'neighborhoods served',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
RichText(
|
||||
text: const TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: '1,000+ Properties\n',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'bought and sold for our clients.',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// Rating visual
|
||||
const SizedBox(width: 16),
|
||||
Column(
|
||||
children: [
|
||||
const Text(
|
||||
'4.9',
|
||||
style: TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: List.generate(
|
||||
5,
|
||||
(index) => Icon(
|
||||
index < 4 ? Icons.star : Icons.star_half,
|
||||
color: AppColors.accentOrange,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user