feat: Implement expandable expertise tags on the agent detail screen and adjust chat screen lifecycle to clear active conversation in deactivate.
This commit is contained in:
@@ -742,33 +742,7 @@ class _AgentDetailScreenState extends ConsumerState<AgentDetailScreen> {
|
|||||||
// Expertise tags (matching web ProfileCard)
|
// Expertise tags (matching web ProfileCard)
|
||||||
if (state.expertiseTags.isNotEmpty) ...[
|
if (state.expertiseTags.isNotEmpty) ...[
|
||||||
const SizedBox(height: 14),
|
const SizedBox(height: 14),
|
||||||
Wrap(
|
_ExpandableTagsWrap(tags: state.expertiseTags),
|
||||||
alignment: WrapAlignment.center,
|
|
||||||
spacing: 8,
|
|
||||||
runSpacing: 8,
|
|
||||||
children: state.expertiseTags
|
|
||||||
.map((tag) => Container(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 12, vertical: 5),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
border: Border.all(
|
|
||||||
color: AppColors.primaryDark,
|
|
||||||
width: 0.7,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
tag,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontFamily: 'SourceSerif4',
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
color: AppColors.primaryDark,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
// Bio with Show More / Show Less
|
// Bio with Show More / Show Less
|
||||||
if (state.descriptionText.isNotEmpty) ...[
|
if (state.descriptionText.isNotEmpty) ...[
|
||||||
@@ -1225,6 +1199,81 @@ class _AgentDetailScreenState extends ConsumerState<AgentDetailScreen> {
|
|||||||
|
|
||||||
// ── Expandable Chips Section ──
|
// ── Expandable Chips Section ──
|
||||||
|
|
||||||
|
class _ExpandableTagsWrap extends StatefulWidget {
|
||||||
|
final List<String> tags;
|
||||||
|
final int initialCount;
|
||||||
|
|
||||||
|
const _ExpandableTagsWrap({required this.tags, this.initialCount = 6});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_ExpandableTagsWrap> createState() => _ExpandableTagsWrapState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ExpandableTagsWrapState extends State<_ExpandableTagsWrap> {
|
||||||
|
bool _expanded = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final displayTags =
|
||||||
|
_expanded ? widget.tags : widget.tags.take(widget.initialCount).toList();
|
||||||
|
final hasMore = widget.tags.length > widget.initialCount;
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: displayTags
|
||||||
|
.map((tag) => Container(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 5),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
width: 0.7,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
tag,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: AppColors.primaryDark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
if (hasMore) ...[
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => setState(() => _expanded = !_expanded),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
border: Border.all(color: AppColors.accentOrange, width: 0.7),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
_expanded ? 'Show Less' : 'Show More',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontFamily: 'SourceSerif4',
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: AppColors.accentOrange,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _ExpandableChipsSection extends StatefulWidget {
|
class _ExpandableChipsSection extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final List<String> items;
|
final List<String> items;
|
||||||
|
|||||||
@@ -675,10 +675,11 @@ class _AgentCardState extends State<_AgentCard> {
|
|||||||
// Specialization tags
|
// Specialization tags
|
||||||
if (specializations.isNotEmpty) ...[
|
if (specializations.isNotEmpty) ...[
|
||||||
Wrap(
|
Wrap(
|
||||||
spacing: 8,
|
alignment: WrapAlignment.start,
|
||||||
runSpacing: 8,
|
spacing: 6,
|
||||||
|
runSpacing: 6,
|
||||||
children: specializations
|
children: specializations
|
||||||
.take(8)
|
.take(6)
|
||||||
.map((tag) => _buildTag(tag))
|
.map((tag) => _buildTag(tag))
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
@@ -797,18 +798,21 @@ class _AgentCardState extends State<_AgentCard> {
|
|||||||
|
|
||||||
Widget _buildTag(String label) {
|
Widget _buildTag(String label) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
height: 28,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(15),
|
borderRadius: BorderRadius.circular(14),
|
||||||
border: Border.all(color: AppColors.primaryDark, width: 0.7),
|
border: Border.all(color: AppColors.primaryDark, width: 0.7),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
label,
|
label,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontFamily: 'SourceSerif4',
|
fontFamily: 'SourceSerif4',
|
||||||
fontSize: 14,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: AppColors.primaryDark,
|
color: AppColors.primaryDark,
|
||||||
|
height: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -441,7 +441,8 @@ class _TopProfessionalsSectionState
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
Wrap(
|
Wrap(
|
||||||
spacing: 8,
|
alignment: WrapAlignment.start,
|
||||||
|
spacing: 6,
|
||||||
runSpacing: 6,
|
runSpacing: 6,
|
||||||
children: expertiseTags
|
children: expertiseTags
|
||||||
.take(6)
|
.take(6)
|
||||||
@@ -594,9 +595,11 @@ class _TopProfessionalsSectionState
|
|||||||
|
|
||||||
Widget _buildTag(String label) {
|
Widget _buildTag(String label) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
height: 28,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(15),
|
borderRadius: BorderRadius.circular(14),
|
||||||
border: Border.all(color: AppColors.primaryDark, width: 0.7),
|
border: Border.all(color: AppColors.primaryDark, width: 0.7),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -606,6 +609,7 @@ class _TopProfessionalsSectionState
|
|||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: AppColors.primaryDark,
|
color: AppColors.primaryDark,
|
||||||
|
height: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -90,6 +90,14 @@ class _ChatScreenState extends ConsumerState<ChatScreen>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@override
|
||||||
|
void deactivate() {
|
||||||
|
// Clear active conversation while ref is still valid (before dispose)
|
||||||
|
ref.read(messagingProvider.notifier).setActiveConversation(null);
|
||||||
|
super.deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
@@ -99,7 +107,6 @@ class _ChatScreenState extends ConsumerState<ChatScreen>
|
|||||||
_socket.stopTyping(widget.conversationId);
|
_socket.stopTyping(widget.conversationId);
|
||||||
}
|
}
|
||||||
_socket.leaveConversation(widget.conversationId);
|
_socket.leaveConversation(widget.conversationId);
|
||||||
ref.read(messagingProvider.notifier).setActiveConversation(null);
|
|
||||||
PushNotificationService().activeConversationId = null;
|
PushNotificationService().activeConversationId = null;
|
||||||
_messageController.dispose();
|
_messageController.dispose();
|
||||||
_scrollController.dispose();
|
_scrollController.dispose();
|
||||||
|
|||||||
Reference in New Issue
Block a user