feat(directory): refactor contact card layout for improved readability and interaction

This commit is contained in:
Vaibhav Surve 2025-07-05 17:29:35 +05:30
parent e7940941ed
commit 606c5e5971

View File

@ -303,6 +303,7 @@ class DirectoryMainScreen extends StatelessWidget {
final firstName = nameParts.first; final firstName = nameParts.first;
final lastName = nameParts.length > 1 ? nameParts.last : ""; final lastName = nameParts.length > 1 ? nameParts.last : "";
final tags = contact.tags.map((tag) => tag.name).toList(); final tags = contact.tags.map((tag) => tag.name).toList();
return InkWell( return InkWell(
onTap: () { onTap: () {
Get.to(() => ContactDetailScreen(contact: contact)); Get.to(() => ContactDetailScreen(contact: contact));
@ -310,41 +311,41 @@ class DirectoryMainScreen extends StatelessWidget {
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 12.0, vertical: 10), horizontal: 12.0, vertical: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Leading Icon
Avatar(
firstName: firstName,
lastName: lastName,
size: 45,
),
MySpacing.width(12),
// Middle Content
Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
MyText.titleSmall( // Top Row: Avatar, Info, Icons
contact.name, Row(
fontWeight: 600, crossAxisAlignment: CrossAxisAlignment.start,
overflow: TextOverflow.ellipsis, children: [
), // Avatar
MyText.bodySmall( Avatar(
contact.organization, firstName: firstName,
color: Colors.grey[700], lastName: lastName,
overflow: TextOverflow.ellipsis, size: 35),
), MySpacing.width(12),
MySpacing.height(6),
// Launcher Row // Middle: Contact Info (wrap with Flexible instead of Expanded)
Column( Flexible(
fit: FlexFit.tight,
child: Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
children: [ children: [
MyText.titleSmall(contact.name,
fontWeight: 600,
overflow: TextOverflow.ellipsis),
MyText.bodySmall(contact.organization,
color: Colors.grey[700],
overflow: TextOverflow.ellipsis),
MySpacing.height(6),
// Emails
...contact.contactEmails.map((e) => ...contact.contactEmails.map((e) =>
GestureDetector( Padding(
padding: const EdgeInsets.only(
bottom: 4),
child: GestureDetector(
onTap: () => onTap: () =>
LauncherUtils.launchEmail( LauncherUtils.launchEmail(
e.emailAddress), e.emailAddress),
@ -352,21 +353,14 @@ class DirectoryMainScreen extends StatelessWidget {
LauncherUtils.copyToClipboard( LauncherUtils.copyToClipboard(
e.emailAddress, e.emailAddress,
typeLabel: 'Email'), typeLabel: 'Email'),
child: Padding(
padding: const EdgeInsets.only(
bottom: 4),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
const Icon( const Icon(
Icons.email_outlined, Icons.email_outlined,
size: 16, size: 16,
color: Colors.indigo), color: Colors.indigo),
MySpacing.width(4), MySpacing.width(4),
ConstrainedBox( Flexible(
constraints:
const BoxConstraints(
maxWidth: 180),
child: MyText.labelSmall( child: MyText.labelSmall(
e.emailAddress, e.emailAddress,
overflow: overflow:
@ -380,30 +374,29 @@ class DirectoryMainScreen extends StatelessWidget {
), ),
), ),
)), )),
// Phones
...contact.contactPhones.map((p) => ...contact.contactPhones.map((p) =>
GestureDetector( Padding(
padding: const EdgeInsets.only(
bottom: 4),
child: GestureDetector(
onTap: () => onTap: () =>
LauncherUtils.launchPhone( LauncherUtils.launchPhone(
p.phoneNumber), p.phoneNumber),
onLongPress: () => onLongPress: () =>
LauncherUtils.copyToClipboard( LauncherUtils.copyToClipboard(
p.phoneNumber, p.phoneNumber,
typeLabel: 'Phone number'), typeLabel:
child: Padding( 'Phone number'),
padding: const EdgeInsets.only(
bottom: 4),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min,
children: [ children: [
const Icon( const Icon(
Icons.phone_outlined, Icons.phone_outlined,
size: 16, size: 16,
color: Colors.indigo), color: Colors.indigo),
MySpacing.width(4), MySpacing.width(4),
ConstrainedBox( Flexible(
constraints:
const BoxConstraints(
maxWidth: 160),
child: MyText.labelSmall( child: MyText.labelSmall(
p.phoneNumber, p.phoneNumber,
overflow: overflow:
@ -419,22 +412,13 @@ class DirectoryMainScreen extends StatelessWidget {
)), )),
], ],
), ),
),
if (tags.isNotEmpty) ...[ // Right: Arrow + WhatsApp
MySpacing.height(4), MySpacing.width(
MyText.labelSmall( 8), // spacing between content and right column
tags.join(', '),
color: Colors.grey[500],
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
],
),
),
// WhatsApp launcher icon
Column( Column(
mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
const Icon(Icons.arrow_forward_ios, const Icon(Icons.arrow_forward_ios,
color: Colors.grey, size: 16), color: Colors.grey, size: 16),
@ -446,13 +430,46 @@ class DirectoryMainScreen extends StatelessWidget {
child: const FaIcon( child: const FaIcon(
FontAwesomeIcons.whatsapp, FontAwesomeIcons.whatsapp,
color: Colors.green, color: Colors.green,
size: 20, size: 20),
),
), ),
], ],
), ),
], ],
), ),
// Bottom Row: Tags as chips aligned to right
if (tags.isNotEmpty) ...[
MySpacing.height(5),
Align(
alignment: Alignment.centerRight,
child: Wrap(
spacing: 8,
runSpacing: 6,
alignment: WrapAlignment.end,
children: tags
.map(
(tag) => Container(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: Colors.indigo.shade50,
borderRadius:
BorderRadius.circular(8),
),
child: MyText.labelSmall(
tag,
fontWeight: 600,
color: Colors.indigo,
overflow: TextOverflow.ellipsis,
),
),
)
.toList(),
),
),
],
],
),
), ),
); );
}, },