feat: Implement S3 image handling with a new resolver and widget, update agent display, and configure storage base URL.
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:real_estate_mobile/config/app_config.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/features/agents/data/models/agent_profile.dart';
|
||||
import 'package:real_estate_mobile/features/agents/data/models/agent_type.dart';
|
||||
import 'package:real_estate_mobile/features/agents/presentation/providers/search_agents_provider.dart';
|
||||
@@ -110,6 +109,8 @@ class _AgentSearchScreenState extends ConsumerState<AgentSearchScreen> {
|
||||
color: Colors.black.withValues(alpha: 0.5),
|
||||
),
|
||||
border: InputBorder.none,
|
||||
enabledBorder: InputBorder.none,
|
||||
focusedBorder: InputBorder.none,
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 14,
|
||||
vertical: 10,
|
||||
@@ -408,16 +409,6 @@ class _AgentCard extends StatefulWidget {
|
||||
class _AgentCardState extends State<_AgentCard> {
|
||||
bool _bioExpanded = false;
|
||||
|
||||
String? _resolveImageUrl(String? imageUrl) {
|
||||
if (imageUrl == null || imageUrl.isEmpty) return null;
|
||||
if (imageUrl.startsWith('http://') || imageUrl.startsWith('https://')) {
|
||||
return imageUrl;
|
||||
}
|
||||
final baseUrl = AppConfig.apiBaseUrl;
|
||||
if (baseUrl.isNotEmpty) return '$baseUrl$imageUrl';
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final agent = widget.agent;
|
||||
@@ -432,6 +423,13 @@ class _AgentCardState extends State<_AgentCard> {
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(color: AppColors.primaryDark.withValues(alpha: 0.1)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFFD9D9D9).withValues(alpha: 0.5),
|
||||
offset: const Offset(0, 10),
|
||||
blurRadius: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Column(
|
||||
@@ -440,7 +438,17 @@ class _AgentCardState extends State<_AgentCard> {
|
||||
// Cover image with match badge
|
||||
Stack(
|
||||
children: [
|
||||
_buildCoverImage(agent),
|
||||
S3Image(
|
||||
imageUrl: agent.avatarUrl,
|
||||
width: double.infinity,
|
||||
height: 265,
|
||||
errorWidget: (_) => Container(
|
||||
width: double.infinity,
|
||||
height: 265,
|
||||
color: AppColors.gradientStart,
|
||||
child: const Icon(Icons.person, size: 80, color: AppColors.primaryDark),
|
||||
),
|
||||
),
|
||||
if (matchPercent != null)
|
||||
Positioned(
|
||||
top: 0,
|
||||
@@ -534,7 +542,7 @@ class _AgentCardState extends State<_AgentCard> {
|
||||
|
||||
// Headline / title
|
||||
Text(
|
||||
agent.headline ?? agent.agentType?.name ?? 'Licensed Real Estate Agent',
|
||||
agent.agentType?.name ?? agent.headline ?? 'Professional',
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Fractul',
|
||||
fontSize: 15,
|
||||
@@ -581,13 +589,16 @@ class _AgentCardState extends State<_AgentCard> {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
const Text(
|
||||
'Member Since 2024',
|
||||
style: TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.primaryDark,
|
||||
Flexible(
|
||||
child: Text(
|
||||
agent.memberSinceText,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'SourceSerif4',
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.primaryDark,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -652,31 +663,6 @@ class _AgentCardState extends State<_AgentCard> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCoverImage(AgentProfile agent) {
|
||||
final resolvedUrl = _resolveImageUrl(agent.avatarUrl);
|
||||
|
||||
if (resolvedUrl != null) {
|
||||
return CachedNetworkImage(
|
||||
imageUrl: resolvedUrl,
|
||||
width: double.infinity,
|
||||
height: 265,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (_, __) => _buildPlaceholder(),
|
||||
errorWidget: (_, __, ___) => _buildPlaceholder(),
|
||||
);
|
||||
}
|
||||
return _buildPlaceholder();
|
||||
}
|
||||
|
||||
Widget _buildPlaceholder() {
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
height: 265,
|
||||
color: AppColors.gradientStart,
|
||||
child:
|
||||
const Icon(Icons.person, size: 80, color: AppColors.primaryDark),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTag(String label) {
|
||||
return Container(
|
||||
|
||||
Reference in New Issue
Block a user