feat(directory): enhance contact card UI with improved layout and interaction elements

This commit is contained in:
Vaibhav Surve 2025-07-04 17:29:26 +05:30
parent 549d8cce3c
commit becdec1a79

View File

@ -2,10 +2,8 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:marco/controller/directory/directory_controller.dart';
import 'package:marco/controller/project_controller.dart';
import 'package:marco/helpers/widgets/my_card.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/utils/my_shadow.dart';
import 'package:marco/helpers/widgets/avatar.dart';
import 'package:marco/helpers/widgets/my_custom_skeleton.dart';
import 'package:marco/model/directory/directory_filter_bottom_sheet.dart';
@ -31,7 +29,7 @@ class DirectoryMainScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F5F5),
backgroundColor: Colors.white,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(72),
child: AppBar(
@ -308,218 +306,145 @@ class DirectoryMainScreen extends StatelessWidget {
final firstName = nameParts.first;
final lastName = nameParts.length > 1 ? nameParts.last : "";
final tags = contact.tags.map((tag) => tag.name).toList();
return MyCard.bordered(
margin: MySpacing.only(bottom: 2),
paddingAll: 8,
borderRadiusAll: 8,
shadow: MyShadow(
elevation: 1.5,
position: MyShadowPosition.bottom,
),
return InkWell(
onTap: () {
Get.to(() => ContactDetailScreen(contact: contact));
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12.0, vertical: 10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Leading Icon
Avatar(
firstName: firstName,
lastName: lastName,
size: 31,
size: 45,
),
MySpacing.width(12),
// Middle Content
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.titleSmall(
contact.name,
fontWeight: 700,
color: Colors.black87,
fontWeight: 600,
overflow: TextOverflow.ellipsis,
),
MyText.bodySmall(
contact.organization,
fontWeight: 500,
color: Colors.grey[700],
overflow: TextOverflow.ellipsis,
),
],
),
),
GestureDetector(
onTap: () {
Get.to(() =>
ContactDetailScreen(contact: contact));
},
child: const Icon(Icons.arrow_forward_ios,
color: Colors.black, size: 15),
),
MySpacing.width(4),
],
),
const Divider(),
if (contact.contactEmails.isNotEmpty ||
contact.contactPhones.isNotEmpty)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Email Row
if (contact.contactEmails.isNotEmpty)
Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Row(
MySpacing.height(6),
// Launcher Row
Wrap(
spacing: 12,
runSpacing: 6,
children: [
if (email != '-')
GestureDetector(
onTap: () =>
LauncherUtils.launchEmail(email),
child: const Padding(
padding:
EdgeInsets.only(right: 8.0),
child: Icon(Icons.email_outlined,
color: Colors.blue, size: 25),
),
),
Expanded(
child: GestureDetector(
onTap: () =>
LauncherUtils.launchEmail(
email),
onLongPress: () =>
LauncherUtils.copyToClipboard(
email,
typeLabel: 'Email'),
child: MyText.bodyMedium(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.email_outlined,
size: 16,
color: Colors.indigo),
MySpacing.width(4),
ConstrainedBox(
constraints:
const BoxConstraints(
maxWidth: 120),
child: MyText.labelSmall(
email,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: Colors.blue,
fontWeight: 600,
textAlign: TextAlign.start,
overflow:
TextOverflow.ellipsis,
color: Colors.indigo,
decoration:
TextDecoration.underline,
),
),
),
],
),
),
// Phone Row with icons at the end
if (contact.contactPhones.isNotEmpty)
Row(
children: [
// Phone Icon
Padding(
padding:
const EdgeInsets.only(right: 6.0),
child: GestureDetector(
onTap: () =>
LauncherUtils.launchPhone(phone),
child: const Icon(
Icons.phone_outlined,
color: Colors.blue,
size: 25),
),
),
// Phone number text
Expanded(
child: GestureDetector(
if (phone != '-')
GestureDetector(
onTap: () =>
LauncherUtils.launchPhone(phone),
onLongPress: () =>
LauncherUtils.copyToClipboard(
phone,
typeLabel: 'Phone number'),
child: MyText.bodyMedium(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.phone_outlined,
size: 16,
color: Colors.indigo),
MySpacing.width(4),
ConstrainedBox(
constraints:
const BoxConstraints(
maxWidth: 100),
child: MyText.labelSmall(
phone,
maxLines: 1,
overflow: TextOverflow.ellipsis,
color: Colors.blue,
fontWeight: 600,
textAlign: TextAlign.start,
overflow:
TextOverflow.ellipsis,
color: Colors.indigo,
decoration:
TextDecoration.underline,
),
),
],
),
),
],
),
// WhatsApp Icon
Padding(
padding:
const EdgeInsets.only(right: 6.0),
child: GestureDetector(
if (tags.isNotEmpty) ...[
MySpacing.height(4),
MyText.labelSmall(
tags.join(', '),
color: Colors.grey[500],
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
],
),
),
// WhatsApp launcher icon
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.arrow_forward_ios,
color: Colors.grey, size: 16),
MySpacing.height(12),
if (phone != '-')
GestureDetector(
onTap: () =>
LauncherUtils.launchWhatsApp(
phone),
LauncherUtils.launchWhatsApp(phone),
child: const FaIcon(
FontAwesomeIcons.whatsapp,
color: Colors.green,
size: 25),
size: 20,
),
),
],
),
],
),
MySpacing.height(8),
// Tags Section
if (tags.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
reverse:
true, // ensures scroll starts from right
child: Row(
children: tags.map((name) {
return Container(
margin:
const EdgeInsets.only(left: 6),
child: TextButton(
onPressed: () {},
style: TextButton.styleFrom(
padding:
const EdgeInsets.symmetric(
horizontal: 10,
vertical: 4,
),
backgroundColor:
const Color.fromARGB(
255, 179, 207, 246),
tapTargetSize:
MaterialTapTargetSize
.shrinkWrap,
minimumSize: Size.zero,
visualDensity:
VisualDensity.standard,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5),
),
),
child: Text(
name,
style: const TextStyle(
fontSize: 10,
color: Color.fromARGB(
255, 0, 0, 0),
height: 1.2,
),
),
),
);
}).toList(),
),
),
],
),
),
],
),
);
},