feat: Implement pull-to-refresh functionality on the agent detail screen by adding a refresh method to the provider and integrating a RefreshIndicator.

This commit is contained in:
pradeepkumar
2026-03-14 23:52:45 +05:30
parent d3f49565d3
commit de4a7b8040
3 changed files with 49 additions and 15 deletions

View File

@@ -324,7 +324,7 @@ class AboutScreen extends ConsumerWidget {
_buildBannerCaption(state.hero.bannerOverlayText), _buildBannerCaption(state.hero.bannerOverlayText),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildStatsRow(state.stats), _buildStatsRow(state.stats),
const SizedBox(height: 32), const SizedBox(height: 24),
_buildSectionTitle(state.featuresBadge), _buildSectionTitle(state.featuresBadge),
const SizedBox(height: 12), const SizedBox(height: 12),
_buildWhyChooseUsSubtitle(), _buildWhyChooseUsSubtitle(),
@@ -333,11 +333,11 @@ class AboutScreen extends ConsumerWidget {
padding: const EdgeInsets.only(bottom: 15), padding: const EdgeInsets.only(bottom: 15),
child: _buildFeatureCard(f), child: _buildFeatureCard(f),
)), )),
const SizedBox(height: 25), const SizedBox(height: 20),
_buildTeamSection(context, ref, state), _buildTeamSection(context, ref, state),
const SizedBox(height: 40), const SizedBox(height: 24),
_buildCtaSection(context, state.cta), _buildCtaSection(context, state.cta),
const SizedBox(height: 30), const SizedBox(height: 24),
], ],
), ),
); );
@@ -606,7 +606,7 @@ class AboutScreen extends ConsumerWidget {
), ),
), ),
), ),
const SizedBox(height: 40), const SizedBox(height: 20),
// Team carousel // Team carousel
SizedBox( SizedBox(
height: 330, height: 330,
@@ -640,7 +640,7 @@ class AboutScreen extends ConsumerWidget {
child: SizedBox( child: SizedBox(
height: 211, height: 211,
width: double.infinity, width: double.infinity,
child: _buildTeamMemberImage(member.imageUrl), child: _buildTeamMemberImage(member.imageUrl, index),
), ),
), ),
), ),
@@ -717,10 +717,19 @@ class AboutScreen extends ConsumerWidget {
} }
// -- Team member image (handles asset://, S3 keys, and URLs) -- // -- Team member image (handles asset://, S3 keys, and URLs) --
Widget _buildTeamMemberImage(String imageUrl) { // Falls back to local professional-N.jpg assets when CMS image fails.
const placeholder = _TeamMemberPlaceholder(); Widget _buildTeamMemberImage(String imageUrl, int index) {
// Local fallback asset based on index
final fallbackAsset = 'assets/images/professional-${index + 1}.jpg';
Widget fallbackImage() => Image.asset(
fallbackAsset,
height: 211,
width: double.infinity,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => const _TeamMemberPlaceholder(),
);
if (imageUrl.isEmpty) return placeholder; if (imageUrl.isEmpty) return fallbackImage();
// Local asset images (defaults) // Local asset images (defaults)
if (imageUrl.startsWith('asset://')) { if (imageUrl.startsWith('asset://')) {
@@ -730,17 +739,17 @@ class AboutScreen extends ConsumerWidget {
height: 211, height: 211,
width: double.infinity, width: double.infinity,
fit: BoxFit.cover, fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) => placeholder, errorBuilder: (_, __, ___) => fallbackImage(),
); );
} }
// S3 key or URL from CMS // S3 key or URL from CMS — fall back to local asset on error
return S3Image( return S3Image(
imageUrl: imageUrl, imageUrl: imageUrl,
height: 211, height: 211,
fit: BoxFit.cover, fit: BoxFit.cover,
placeholder: (_) => placeholder, placeholder: (_) => fallbackImage(),
errorWidget: (_) => placeholder, errorWidget: (_) => fallbackImage(),
); );
} }

View File

@@ -399,6 +399,24 @@ class AgentDetailNotifier extends StateNotifier<AgentDetailState> {
} }
} }
Future<void> refresh() async {
try {
final results = await Future.wait([
_repo.getAgentById(agentId),
_repo.getFieldValues(agentId),
_repo.getTestimonials(agentId),
]);
state = state.copyWith(
agent: results[0] as AgentProfile,
fieldValues: results[1] as List<AgentFieldValue>,
testimonials: results[2] as List<Map<String, dynamic>>,
isLoading: false,
);
// Also refresh connection status
await loadConnectionStatus();
} catch (_) {}
}
Future<void> loadConnectionStatus() async { Future<void> loadConnectionStatus() async {
final status = await _repo.getConnectionStatus(agentId); final status = await _repo.getConnectionStatus(agentId);
state = state.copyWith(connectionStatus: status); state = state.copyWith(connectionStatus: status);

View File

@@ -92,8 +92,14 @@ class _AgentDetailScreenState extends ConsumerState<AgentDetailScreen> {
Widget _buildContent(AgentDetailState state) { Widget _buildContent(AgentDetailState state) {
final agent = state.agent!; final agent = state.agent!;
return SingleChildScrollView( return RefreshIndicator(
child: Column( color: AppColors.accentOrange,
onRefresh: () => ref
.read(agentDetailProvider(widget.agentId).notifier)
.refresh(),
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: [ children: [
// ── Avatar Section ── // ── Avatar Section ──
const SizedBox(height: 16), const SizedBox(height: 16),
@@ -132,6 +138,7 @@ class _AgentDetailScreenState extends ConsumerState<AgentDetailScreen> {
const SizedBox(height: 30), const SizedBox(height: 30),
], ],
), ),
),
); );
} }