Files
mobile-app/lib/features/home/presentation/widgets/trust_stats_section.dart

160 lines
5.1 KiB
Dart
Raw Normal View History

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:real_estate_mobile/core/constants/app_colors.dart';
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';
/// 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 {
const TrustStatsSection({super.key});
@override
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;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
children: [
Text(
title,
textAlign: TextAlign.center,
style: const TextStyle(
fontFamily: 'Fractul',
fontSize: 25,
fontWeight: FontWeight.w700,
color: AppColors.primaryDark,
),
),
const SizedBox(height: 16),
Text(
subtitle,
textAlign: TextAlign.center,
style: const 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 (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(),
),
),
),
],
),
);
}
Widget _buildStatItem(StatItem stat) {
final iconEntry = _statIconMap[stat.iconPath];
final svgPath = iconEntry?.$1;
final fallbackIcon = iconEntry?.$2 ?? Icons.info_outline;
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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(
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,
),
),
],
),
),
),
],
);
}
}