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:
@@ -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(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user