feat: add static agent carousel with navigation dots to the FeaturesSection.
This commit is contained in:
BIN
assets/images/agent-anderson.jpg
Normal file
BIN
assets/images/agent-anderson.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 MiB |
BIN
assets/images/agent-daniel.jpg
Normal file
BIN
assets/images/agent-daniel.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 MiB |
BIN
assets/images/agent-deepak.jpg
Normal file
BIN
assets/images/agent-deepak.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 MiB |
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
import 'package:real_estate_mobile/features/home/presentation/widgets/featured_professionals_section.dart';
|
|
||||||
import 'package:real_estate_mobile/features/home/presentation/widgets/features_section.dart';
|
import 'package:real_estate_mobile/features/home/presentation/widgets/features_section.dart';
|
||||||
import 'package:real_estate_mobile/features/home/presentation/widgets/hero_section.dart';
|
import 'package:real_estate_mobile/features/home/presentation/widgets/hero_section.dart';
|
||||||
import 'package:real_estate_mobile/features/home/presentation/widgets/testimonials_section.dart';
|
import 'package:real_estate_mobile/features/home/presentation/widgets/testimonials_section.dart';
|
||||||
@@ -25,10 +24,6 @@ class HomeScreen extends ConsumerWidget {
|
|||||||
const FeaturesSection(),
|
const FeaturesSection(),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
|
|
||||||
// Featured Professionals Carousel
|
|
||||||
const FeaturedProfessionalsSection(),
|
|
||||||
const SizedBox(height: 40),
|
|
||||||
|
|
||||||
// Top Professionals Section (Agents/Lenders tabs)
|
// Top Professionals Section (Agents/Lenders tabs)
|
||||||
const TopProfessionalsSection(),
|
const TopProfessionalsSection(),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ import 'package:flutter_svg/flutter_svg.dart';
|
|||||||
import 'package:shimmer/shimmer.dart';
|
import 'package:shimmer/shimmer.dart';
|
||||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
import 'package:real_estate_mobile/core/widgets/s3_image.dart';
|
import 'package:real_estate_mobile/core/widgets/s3_image.dart';
|
||||||
import 'package:real_estate_mobile/features/agents/data/models/agent_profile.dart';
|
import 'package:real_estate_mobile/features/home/data/models/landing_page_content.dart';
|
||||||
import 'package:real_estate_mobile/features/agents/presentation/providers/agents_provider.dart';
|
import 'package:real_estate_mobile/features/home/presentation/providers/home_provider.dart';
|
||||||
|
|
||||||
/// Featured professionals carousel shown above the agents/lenders tab section.
|
/// Featured professionals carousel shown above the agents/lenders tab section.
|
||||||
/// Now fetches REAL agent data from GET /agents API (like web does)
|
/// Uses CMS data from the admin panel (Top Professionals section).
|
||||||
/// instead of using CMS/hardcoded fallback data.
|
|
||||||
class FeaturedProfessionalsSection extends ConsumerStatefulWidget {
|
class FeaturedProfessionalsSection extends ConsumerStatefulWidget {
|
||||||
const FeaturedProfessionalsSection({super.key});
|
const FeaturedProfessionalsSection({super.key});
|
||||||
|
|
||||||
@@ -49,11 +48,13 @@ class _FeaturedProfessionalsSectionState
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// Real agent data from GET /agents API
|
final homeState = ref.watch(homeProvider);
|
||||||
final topProState = ref.watch(topProfessionalsProvider);
|
final cmsContent = homeState.content?.topProfessionals;
|
||||||
final professionals = topProState.agents;
|
|
||||||
|
|
||||||
if (topProState.isLoading) {
|
// Use CMS agents list for the featured carousel
|
||||||
|
final professionals = cmsContent?.agents ?? [];
|
||||||
|
|
||||||
|
if (homeState.isLoading) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 40),
|
padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||||
child: Shimmer.fromColors(
|
child: Shimmer.fromColors(
|
||||||
@@ -89,23 +90,6 @@ class _FeaturedProfessionalsSectionState
|
|||||||
Container(height: 14, width: 180, color: Colors.white),
|
Container(height: 14, width: 180, color: Colors.white),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Container(height: 12, width: 140, color: Colors.white),
|
Container(height: 12, width: 140, color: Colors.white),
|
||||||
const SizedBox(height: 12),
|
|
||||||
Row(
|
|
||||||
children: List.generate(
|
|
||||||
5,
|
|
||||||
(_) => Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 4),
|
|
||||||
child: Container(
|
|
||||||
height: 18,
|
|
||||||
width: 18,
|
|
||||||
decoration: const BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -156,12 +140,7 @@ class _FeaturedProfessionalsSectionState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildFeaturedCard(AgentProfile agent, int index) {
|
Widget _buildFeaturedCard(ProfessionalItem item, int index) {
|
||||||
final rating = agent.averageRating ?? 0.0;
|
|
||||||
final ratingText = rating > 0 ? '${rating.toStringAsFixed(1)} Rating' : '';
|
|
||||||
final subtitle = agent.agentType?.name ?? agent.headline ?? '';
|
|
||||||
final experience = agent.experienceText;
|
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
@@ -175,7 +154,16 @@ class _FeaturedProfessionalsSectionState
|
|||||||
// Image
|
// Image
|
||||||
ClipRRect(
|
ClipRRect(
|
||||||
borderRadius: const BorderRadius.vertical(top: Radius.circular(15)),
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(15)),
|
||||||
child: _buildCardImage(agent, index),
|
child: item.imageUrl.isNotEmpty
|
||||||
|
? S3Image(
|
||||||
|
imageUrl: item.imageUrl,
|
||||||
|
width: double.infinity,
|
||||||
|
height: 192,
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
placeholder: (_) => _buildImagePlaceholder(index),
|
||||||
|
errorWidget: (_) => _buildImagePlaceholder(index),
|
||||||
|
)
|
||||||
|
: _buildImagePlaceholder(index),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
@@ -186,7 +174,7 @@ class _FeaturedProfessionalsSectionState
|
|||||||
children: [
|
children: [
|
||||||
// Name
|
// Name
|
||||||
Text(
|
Text(
|
||||||
agent.fullName,
|
item.name,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: 'Fractul',
|
fontFamily: 'Fractul',
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -197,10 +185,10 @@ class _FeaturedProfessionalsSectionState
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
|
|
||||||
// Subtitle/headline
|
// Subtitle
|
||||||
if (subtitle.isNotEmpty)
|
if (item.subtitle.isNotEmpty)
|
||||||
Text(
|
Text(
|
||||||
subtitle,
|
item.subtitle,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: 'Fractul',
|
fontFamily: 'Fractul',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@@ -212,10 +200,9 @@ class _FeaturedProfessionalsSectionState
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
|
|
||||||
// Verified + Rating row
|
// Verified badge
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
if (agent.isVerified) ...[
|
|
||||||
SvgPicture.asset(
|
SvgPicture.asset(
|
||||||
'assets/icons/verified_badge_icon.svg',
|
'assets/icons/verified_badge_icon.svg',
|
||||||
width: 16,
|
width: 16,
|
||||||
@@ -237,47 +224,27 @@ class _FeaturedProfessionalsSectionState
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
if (agent.isVerified && ratingText.isNotEmpty)
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
if (ratingText.isNotEmpty) ...[
|
|
||||||
SvgPicture.asset(
|
|
||||||
'assets/icons/star_rating_icon.svg',
|
|
||||||
width: 16,
|
|
||||||
height: 16,
|
|
||||||
placeholderBuilder: (_) => const Icon(
|
|
||||||
Icons.star,
|
|
||||||
color: Color(0xFFFFDE21),
|
|
||||||
size: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 4),
|
|
||||||
Text(
|
|
||||||
ratingText,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontFamily: 'SourceSerif4',
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
color: AppColors.primaryDark,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
|
|
||||||
// Location row
|
// Location row
|
||||||
if (agent.location.isNotEmpty)
|
if (item.location.isNotEmpty)
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
SvgPicture.asset(
|
SvgPicture.asset(
|
||||||
'assets/icons/location_pin_icon.svg',
|
'assets/icons/location_orange_icon.svg',
|
||||||
width: 16,
|
width: 16,
|
||||||
height: 16,
|
height: 16,
|
||||||
|
placeholderBuilder: (_) => const Icon(
|
||||||
|
Icons.location_on,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
agent.location,
|
item.location,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: 'SourceSerif4',
|
fontFamily: 'SourceSerif4',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@@ -292,7 +259,7 @@ class _FeaturedProfessionalsSectionState
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
// Experience
|
// Experience
|
||||||
if (experience.isNotEmpty)
|
if (item.experience.isNotEmpty)
|
||||||
RichText(
|
RichText(
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
children: [
|
children: [
|
||||||
@@ -306,7 +273,7 @@ class _FeaturedProfessionalsSectionState
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: experience,
|
text: item.experience,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: 'SourceSerif4',
|
fontFamily: 'SourceSerif4',
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
@@ -327,19 +294,6 @@ class _FeaturedProfessionalsSectionState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Image helpers --
|
|
||||||
|
|
||||||
Widget _buildCardImage(AgentProfile agent, int index) {
|
|
||||||
return S3Image(
|
|
||||||
imageUrl: agent.avatarUrl,
|
|
||||||
width: double.infinity,
|
|
||||||
height: 192,
|
|
||||||
alignment: Alignment.topCenter,
|
|
||||||
placeholder: (_) => _buildImagePlaceholder(index),
|
|
||||||
errorWidget: (_) => _buildImagePlaceholder(index),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildImagePlaceholder(int index) {
|
Widget _buildImagePlaceholder(int index) {
|
||||||
const colors = [
|
const colors = [
|
||||||
Color(0xFFC4D9D4),
|
Color(0xFFC4D9D4),
|
||||||
@@ -354,8 +308,6 @@ class _FeaturedProfessionalsSectionState
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Dot indicators --
|
|
||||||
|
|
||||||
Widget _buildDotIndicators(int count) {
|
Widget _buildDotIndicators(int count) {
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
|||||||
@@ -53,11 +53,89 @@ const _iconMap = {
|
|||||||
'/assets/icons/trusted-people-icon.svg': ('assets/icons/trusted_icon.svg', Icons.people_outline),
|
'/assets/icons/trusted-people-icon.svg': ('assets/icons/trusted_icon.svg', Icons.people_outline),
|
||||||
};
|
};
|
||||||
|
|
||||||
class FeaturesSection extends ConsumerWidget {
|
/// Static agent cards — matches web's hardcoded agents in FeaturesSection.
|
||||||
|
const _staticAgents = [
|
||||||
|
_StaticAgent(
|
||||||
|
name: 'Anderson',
|
||||||
|
role: 'Rental & Investment Consultant',
|
||||||
|
rating: '4.9',
|
||||||
|
location: 'New York',
|
||||||
|
experience: '7+ years in the real estate industry.',
|
||||||
|
image: 'assets/images/agent-anderson.jpg',
|
||||||
|
),
|
||||||
|
_StaticAgent(
|
||||||
|
name: 'Deepak',
|
||||||
|
role: 'Rental & Investment Consultant',
|
||||||
|
rating: '4.9',
|
||||||
|
location: 'New York',
|
||||||
|
experience: '7+ years in the real estate industry.',
|
||||||
|
image: 'assets/images/agent-deepak.jpg',
|
||||||
|
),
|
||||||
|
_StaticAgent(
|
||||||
|
name: 'Daniel',
|
||||||
|
role: 'Rental & Investment Consultant',
|
||||||
|
rating: '4.9',
|
||||||
|
location: 'New York',
|
||||||
|
experience: '7+ years in the real estate industry.',
|
||||||
|
image: 'assets/images/agent-daniel.jpg',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
class _StaticAgent {
|
||||||
|
final String name;
|
||||||
|
final String role;
|
||||||
|
final String rating;
|
||||||
|
final String location;
|
||||||
|
final String experience;
|
||||||
|
final String image;
|
||||||
|
|
||||||
|
const _StaticAgent({
|
||||||
|
required this.name,
|
||||||
|
required this.role,
|
||||||
|
required this.rating,
|
||||||
|
required this.location,
|
||||||
|
required this.experience,
|
||||||
|
required this.image,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class FeaturesSection extends ConsumerStatefulWidget {
|
||||||
const FeaturesSection({super.key});
|
const FeaturesSection({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
ConsumerState<FeaturesSection> createState() => _FeaturesSectionState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FeaturesSectionState extends ConsumerState<FeaturesSection> {
|
||||||
|
int _currentPage = 0;
|
||||||
|
late ScrollController _agentScrollController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_agentScrollController = ScrollController();
|
||||||
|
_agentScrollController.addListener(_onAgentScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_agentScrollController.removeListener(_onAgentScroll);
|
||||||
|
_agentScrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onAgentScroll() {
|
||||||
|
if (!_agentScrollController.hasClients) return;
|
||||||
|
const cardWidth = 254.0 + 16.0; // card width + padding
|
||||||
|
final page = (_agentScrollController.offset / cardWidth).round();
|
||||||
|
if (page != _currentPage && page >= 0 && page < _staticAgents.length) {
|
||||||
|
setState(() => _currentPage = page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final ref = this.ref;
|
||||||
final homeState = ref.watch(homeProvider);
|
final homeState = ref.watch(homeProvider);
|
||||||
final cmsFeatures = homeState.content?.features;
|
final cmsFeatures = homeState.content?.features;
|
||||||
|
|
||||||
@@ -70,7 +148,9 @@ class FeaturesSection extends ConsumerWidget {
|
|||||||
final subtitle =
|
final subtitle =
|
||||||
data.subtitle.isNotEmpty ? data.subtitle : _defaultFeatures.subtitle;
|
data.subtitle.isNotEmpty ? data.subtitle : _defaultFeatures.subtitle;
|
||||||
|
|
||||||
return Padding(
|
return Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -102,6 +182,42 @@ class FeaturesSection extends ConsumerWidget {
|
|||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
// Static agent cards carousel (same as web)
|
||||||
|
SizedBox(
|
||||||
|
height: 370,
|
||||||
|
child: ListView.builder(
|
||||||
|
controller: _agentScrollController,
|
||||||
|
scrollDirection: Axis.horizontal,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
itemCount: _staticAgents.length,
|
||||||
|
itemBuilder: (context, index) => Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 16),
|
||||||
|
child: _buildStaticAgentCard(_staticAgents[index]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
// Dot indicators
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: List.generate(_staticAgents.length, (index) {
|
||||||
|
final isActive = index == _currentPage;
|
||||||
|
return Container(
|
||||||
|
width: isActive ? 10 : 8,
|
||||||
|
height: isActive ? 10 : 8,
|
||||||
|
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: isActive
|
||||||
|
? AppColors.primaryDark
|
||||||
|
: AppColors.primaryDark.withValues(alpha: 0.3),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,4 +280,189 @@ class FeaturesSection extends ConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildStaticAgentCard(_StaticAgent agent) {
|
||||||
|
return Container(
|
||||||
|
width: 254,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppColors.primaryDark.withValues(alpha: 0.1),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: Color(0x33D9D9D9),
|
||||||
|
blurRadius: 10,
|
||||||
|
offset: Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Image
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius:
|
||||||
|
const BorderRadius.vertical(top: Radius.circular(15)),
|
||||||
|
child: Image.asset(
|
||||||
|
agent.image,
|
||||||
|
width: 254,
|
||||||
|
height: 161,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
errorBuilder: (_, __, ___) => Container(
|
||||||
|
width: 254,
|
||||||
|
height: 161,
|
||||||
|
color: const Color(0xFFC4D9D4),
|
||||||
|
child: const Icon(Icons.person, size: 60, color: AppColors.primaryDark),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Content
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Name
|
||||||
|
Text(
|
||||||
|
agent.name,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
// Role
|
||||||
|
Text(
|
||||||
|
agent.role,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'Fractul',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
// Verified + Rating row
|
||||||
|
Wrap(
|
||||||
|
spacing: 12,
|
||||||
|
runSpacing: 4,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
'assets/icons/verified_badge_icon.svg',
|
||||||
|
width: 14,
|
||||||
|
height: 14,
|
||||||
|
placeholderBuilder: (_) => const Icon(
|
||||||
|
Icons.verified,
|
||||||
|
color: Color(0xFF638559),
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
const Text(
|
||||||
|
'Verified Agent',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
'assets/icons/star_rating_icon.svg',
|
||||||
|
width: 14,
|
||||||
|
height: 14,
|
||||||
|
placeholderBuilder: (_) => const Icon(
|
||||||
|
Icons.star,
|
||||||
|
color: Color(0xFFFFDE21),
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(
|
||||||
|
'${agent.rating} Rating',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
// Location
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
'assets/icons/location_filled_icon.svg',
|
||||||
|
width: 15,
|
||||||
|
height: 15,
|
||||||
|
placeholderBuilder: (_) => const Icon(
|
||||||
|
Icons.location_on,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
size: 15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(
|
||||||
|
agent.location,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
// Experience
|
||||||
|
RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
children: [
|
||||||
|
const TextSpan(
|
||||||
|
text: 'Experience: ',
|
||||||
|
style: TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: agent.experience,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user