2026-02-24 03:19:55 +05:30
|
|
|
import 'package:flutter/material.dart';
|
2026-03-07 10:25:53 +05:30
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
|
import 'package:flutter_svg/flutter_svg.dart';
|
2026-02-24 03:19:55 +05:30
|
|
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
2026-03-07 10:25:53 +05:30
|
|
|
import 'package:real_estate_mobile/features/home/data/models/landing_page_content.dart';
|
|
|
|
|
import 'package:real_estate_mobile/features/home/presentation/providers/home_provider.dart';
|
2026-02-24 03:19:55 +05:30
|
|
|
|
2026-03-07 10:25:53 +05:30
|
|
|
/// Default content — matches web's hardcoded defaultContent fallback.
|
|
|
|
|
const _defaultContent = TestimonialsContent(
|
|
|
|
|
title: "Our Clients' Trust Is Our Foundation",
|
|
|
|
|
subtitle:
|
|
|
|
|
'We help buyers, sellers, and investors close successful real estate deals with confidence in every transaction.',
|
|
|
|
|
ratingInfo:
|
|
|
|
|
'Clients rate our real estate services 4.9 out of 5 on average, based on recent client reviews.',
|
|
|
|
|
stats: [
|
|
|
|
|
StatItem(
|
|
|
|
|
iconPath: 'cities',
|
|
|
|
|
boldText: '25+ Cities &',
|
|
|
|
|
normalText: 'neighborhoods served',
|
|
|
|
|
),
|
|
|
|
|
StatItem(
|
|
|
|
|
iconPath: 'properties',
|
|
|
|
|
boldText: '1,000+ Properties',
|
|
|
|
|
normalText: 'bought and sold for our clients.',
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
testimonials: [],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/// Map of stat icon keys to local SVG asset paths and Material fallback icons.
|
|
|
|
|
const _statIconMap = {
|
|
|
|
|
'cities': ('assets/icons/cities_icon.svg', Icons.location_city),
|
|
|
|
|
'properties': ('assets/icons/properties_icon.svg', Icons.home_work),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class TrustStatsSection extends ConsumerWidget {
|
2026-02-24 03:19:55 +05:30
|
|
|
const TrustStatsSection({super.key});
|
|
|
|
|
|
|
|
|
|
@override
|
2026-03-07 10:25:53 +05:30
|
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
|
|
|
final homeState = ref.watch(homeProvider);
|
|
|
|
|
final cmsTestimonials = homeState.content?.testimonials;
|
|
|
|
|
|
|
|
|
|
// Use CMS data if available, otherwise fallback (same pattern as web)
|
|
|
|
|
final data = cmsTestimonials ?? _defaultContent;
|
|
|
|
|
|
|
|
|
|
final title = data.title.isNotEmpty ? data.title : _defaultContent.title;
|
|
|
|
|
final subtitle =
|
|
|
|
|
data.subtitle.isNotEmpty ? data.subtitle : _defaultContent.subtitle;
|
|
|
|
|
final stats =
|
|
|
|
|
data.stats.isNotEmpty ? data.stats : _defaultContent.stats;
|
|
|
|
|
|
2026-02-24 03:19:55 +05:30
|
|
|
return Padding(
|
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
|
|
|
child: Column(
|
|
|
|
|
children: [
|
2026-03-07 10:25:53 +05:30
|
|
|
Text(
|
|
|
|
|
title,
|
2026-02-24 03:19:55 +05:30
|
|
|
textAlign: TextAlign.center,
|
2026-03-07 10:25:53 +05:30
|
|
|
style: const TextStyle(
|
2026-02-24 03:19:55 +05:30
|
|
|
fontFamily: 'Fractul',
|
|
|
|
|
fontSize: 25,
|
|
|
|
|
fontWeight: FontWeight.w700,
|
|
|
|
|
color: AppColors.primaryDark,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 16),
|
2026-03-07 10:25:53 +05:30
|
|
|
Text(
|
|
|
|
|
subtitle,
|
2026-02-24 03:19:55 +05:30
|
|
|
textAlign: TextAlign.center,
|
2026-03-07 10:25:53 +05:30
|
|
|
style: const TextStyle(
|
2026-02-24 03:19:55 +05:30
|
|
|
fontFamily: 'Fractul',
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
fontWeight: FontWeight.w500,
|
|
|
|
|
color: AppColors.primaryDark,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
|
const Divider(color: AppColors.divider),
|
|
|
|
|
const SizedBox(height: 16),
|
2026-03-14 22:44:48 +05:30
|
|
|
// Stats (group centered, content left-aligned)
|
|
|
|
|
Align(
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
child: IntrinsicWidth(
|
|
|
|
|
child: Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: stats
|
|
|
|
|
.map((stat) => Padding(
|
|
|
|
|
padding: const EdgeInsets.only(bottom: 12),
|
|
|
|
|
child: _buildStatItem(stat),
|
|
|
|
|
))
|
|
|
|
|
.toList(),
|
2026-02-24 03:19:55 +05:30
|
|
|
),
|
2026-03-14 22:44:48 +05:30
|
|
|
),
|
2026-02-24 03:19:55 +05:30
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-03-07 10:25:53 +05:30
|
|
|
|
|
|
|
|
Widget _buildStatItem(StatItem stat) {
|
|
|
|
|
final iconEntry = _statIconMap[stat.iconPath];
|
|
|
|
|
final svgPath = iconEntry?.$1;
|
|
|
|
|
final fallbackIcon = iconEntry?.$2 ?? Icons.info_outline;
|
|
|
|
|
|
|
|
|
|
return Row(
|
2026-03-14 22:44:48 +05:30
|
|
|
mainAxisSize: MainAxisSize.min,
|
2026-03-07 10:25:53 +05:30
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
2026-03-14 22:44:48 +05:30
|
|
|
Padding(
|
|
|
|
|
padding: const EdgeInsets.only(right: 10, top: 2),
|
|
|
|
|
child: svgPath != null
|
|
|
|
|
? SvgPicture.asset(
|
|
|
|
|
svgPath,
|
|
|
|
|
width: 27,
|
|
|
|
|
height: 27,
|
|
|
|
|
placeholderBuilder: (_) => Icon(
|
|
|
|
|
fallbackIcon,
|
|
|
|
|
size: 27,
|
|
|
|
|
color: AppColors.accentOrange,
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
: Icon(
|
|
|
|
|
fallbackIcon,
|
|
|
|
|
size: 27,
|
|
|
|
|
color: AppColors.accentOrange,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Flexible(
|
2026-03-07 10:25:53 +05:30
|
|
|
child: RichText(
|
|
|
|
|
text: TextSpan(
|
|
|
|
|
children: [
|
|
|
|
|
TextSpan(
|
|
|
|
|
text: '${stat.boldText}\n',
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontFamily: 'SourceSerif4',
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
fontWeight: FontWeight.w700,
|
|
|
|
|
color: AppColors.primaryDark,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
TextSpan(
|
|
|
|
|
text: stat.normalText,
|
|
|
|
|
style: const TextStyle(
|
|
|
|
|
fontFamily: 'SourceSerif4',
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
fontWeight: FontWeight.w400,
|
|
|
|
|
color: AppColors.primaryDark,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-24 03:19:55 +05:30
|
|
|
}
|