All checks were successful
/ mirror (push) Successful in 4s
Feat: contact-modal et refonte du contact-state pour la page de favori et possibilité de update les contacts. Aussi mis la composition page avec le service de contact, on évite de fetch dans la page directement Reviewed-on: icing/G-EIP-700-TLS-7-1-eip-stephane.corbiere#10 Co-authored-by: Florian Griffon <florian.griffon@epitech.eu> Co-committed-by: Florian Griffon <florian.griffon@epitech.eu>
229 lines
8.6 KiB
Dart
229 lines
8.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_contacts/flutter_contacts.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
import 'package:dialer/widgets/username_color_generator.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
class ContactModal extends StatelessWidget {
|
|
final Contact contact;
|
|
final Function onEdit;
|
|
final Function onToggleFavorite;
|
|
final bool isFavorite;
|
|
|
|
const ContactModal({
|
|
super.key,
|
|
required this.contact,
|
|
required this.onEdit,
|
|
required this.onToggleFavorite,
|
|
required this.isFavorite,
|
|
});
|
|
|
|
void _launchPhoneDialer(String phoneNumber) async {
|
|
final uri = Uri(scheme: 'tel', path: phoneNumber);
|
|
if (await canLaunchUrl(uri)) {
|
|
await launchUrl(uri);
|
|
} else {
|
|
debugPrint('Could not launch $phoneNumber');
|
|
}
|
|
}
|
|
|
|
void _launchSms(String phoneNumber) async {
|
|
final uri = Uri(scheme: 'sms', path: phoneNumber);
|
|
if (await canLaunchUrl(uri)) {
|
|
await launchUrl(uri);
|
|
} else {
|
|
debugPrint('Could not launch SMS to $phoneNumber');
|
|
}
|
|
}
|
|
|
|
void _launchEmail(String email) async {
|
|
final uri = Uri(scheme: 'mailto', path: email);
|
|
if (await canLaunchUrl(uri)) {
|
|
await launchUrl(uri);
|
|
} else {
|
|
debugPrint('Could not launch email to $email');
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
String phoneNumber = contact.phones.isNotEmpty
|
|
? contact.phones.first.number
|
|
: 'No phone number';
|
|
String email =
|
|
contact.emails.isNotEmpty ? contact.emails.first.address : 'No email';
|
|
|
|
return GestureDetector(
|
|
onTap: () => Navigator.of(context).pop(),
|
|
child: Container(
|
|
color: Colors.black.withOpacity(0.5),
|
|
child: GestureDetector(
|
|
onTap: () {},
|
|
child: FractionallySizedBox(
|
|
heightFactor: 0.7,
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey[900],
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
// Modal Handle
|
|
// Top Bar with Handle and Three-Dot Menu
|
|
Stack(
|
|
children: [
|
|
Align(
|
|
alignment: Alignment.center,
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 10),
|
|
child: Container(
|
|
width: 50,
|
|
height: 5,
|
|
decoration: BoxDecoration(
|
|
color: Colors.grey.shade300,
|
|
borderRadius: BorderRadius.circular(5),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Align(
|
|
alignment: Alignment.topRight,
|
|
child: Padding(
|
|
padding: const EdgeInsets.only(top: 10, right: 10),
|
|
child: PopupMenuButton<String>(
|
|
icon: Icon(Icons.more_vert, color: Colors.white),
|
|
onSelected: (String choice) {
|
|
print(
|
|
'Selected: $choice'); // Placeholder for menu actions
|
|
},
|
|
itemBuilder: (BuildContext context) {
|
|
return <PopupMenuEntry<String>>[
|
|
PopupMenuItem<String>(
|
|
value: 'show_associated_contacts',
|
|
child: Text('Show associated contacts'),
|
|
),
|
|
PopupMenuItem<String>(
|
|
value: 'delete',
|
|
child: Text('Delete'),
|
|
),
|
|
PopupMenuItem<String>(
|
|
value: 'share',
|
|
child: Text('Share (via QR code)'),
|
|
),
|
|
PopupMenuItem<String>(
|
|
value: 'create_shortcut',
|
|
child:
|
|
Text('Create shortcut (to home screen)'),
|
|
),
|
|
PopupMenuItem<String>(
|
|
value: 'set_ringtone',
|
|
child: Text('Set ringtone'),
|
|
),
|
|
];
|
|
},
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
|
|
// Contact Profile
|
|
Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Column(
|
|
children: [
|
|
CircleAvatar(
|
|
radius: 50,
|
|
backgroundImage: (contact.thumbnail != null &&
|
|
contact.thumbnail!.isNotEmpty)
|
|
? MemoryImage(contact.thumbnail!)
|
|
: null,
|
|
backgroundColor:
|
|
generateColorFromName(contact.displayName),
|
|
child: (contact.thumbnail == null ||
|
|
contact.thumbnail!.isEmpty)
|
|
? Text(
|
|
contact.displayName.isNotEmpty
|
|
? contact.displayName[0].toUpperCase()
|
|
: '?',
|
|
style: TextStyle(
|
|
fontSize: 40, color: Colors.white),
|
|
)
|
|
: null,
|
|
),
|
|
SizedBox(height: 10),
|
|
Text(
|
|
contact.displayName,
|
|
style: TextStyle(
|
|
fontSize: 24, fontWeight: FontWeight.bold),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
// Contact Actions
|
|
Divider(),
|
|
ListTile(
|
|
leading: Icon(Icons.phone, color: Colors.green),
|
|
title: Text(phoneNumber),
|
|
onTap: () {
|
|
if (contact.phones.isNotEmpty) {
|
|
_launchPhoneDialer(phoneNumber);
|
|
}
|
|
},
|
|
),
|
|
ListTile(
|
|
leading: Icon(Icons.message, color: Colors.blue),
|
|
title: Text(phoneNumber),
|
|
onTap: () {
|
|
if (contact.phones.isNotEmpty) {
|
|
_launchSms(phoneNumber);
|
|
}
|
|
},
|
|
),
|
|
ListTile(
|
|
leading: Icon(Icons.email, color: Colors.orange),
|
|
title: Text(email),
|
|
onTap: () {
|
|
if (contact.emails.isNotEmpty) {
|
|
_launchEmail(email);
|
|
}
|
|
},
|
|
),
|
|
Divider(),
|
|
// Favorite and Edit Buttons
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
ElevatedButton.icon(
|
|
onPressed: () {
|
|
Navigator.of(context).pop();
|
|
onToggleFavorite();
|
|
},
|
|
icon: Icon(contact.isStarred
|
|
? Icons.star
|
|
: Icons.star_border),
|
|
label: Text(
|
|
contact.isStarred ? 'Unfavorite' : 'Favorite'),
|
|
),
|
|
ElevatedButton.icon(
|
|
onPressed: () => onEdit(),
|
|
icon: Icon(Icons.edit),
|
|
label: Text('Edit Contact'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
SizedBox(height: 16),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|