feat: add MessageService for sending SMS and integrate into ContactModal
All checks were successful
/ mirror (push) Successful in 5s
/ build (push) Successful in 10m40s
/ build-stealth (push) Successful in 10m34s

This commit is contained in:
AlexisDanlos 2025-05-11 12:11:32 +02:00
parent afa0c5b5a4
commit 4ecf7c546b
2 changed files with 43 additions and 32 deletions

View File

@ -0,0 +1,18 @@
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart';
import 'package:url_launcher/url_launcher.dart';
/// A service to handle sending SMS messages using the url_launcher package.
class MessageService {
/// Launches the SMS dialer for the given [phoneNumber].
Future<void> sendSms(String phoneNumber) async {
// Sanitize number (keep only digits and plus sign)
final sanitized = phoneNumber.replaceAll(RegExp(r'[^0-9+]'), '');
Uri uri;
uri = Uri(scheme: 'sms', path: sanitized);
await launchUrl(uri);
}
}

View File

@ -7,6 +7,7 @@ import '../../../../domain/services/obfuscate_service.dart';
import '../../../../domain/services/block_service.dart';
import '../../../../domain/services/contact_service.dart';
import '../../../../domain/services/call_service.dart';
import '../../../../domain/services/message_service.dart';
class ContactModal extends StatefulWidget {
final Contact contact;
@ -32,6 +33,7 @@ class _ContactModalState extends State<ContactModal> {
final ObfuscateService _obfuscateService = ObfuscateService();
final CallService _callService = CallService();
final ContactService _contactService = ContactService();
final MessageService _messageService = MessageService();
@override
void initState() {
@ -60,7 +62,7 @@ class _ContactModalState extends State<ContactModal> {
);
return;
}
if (isBlocked) {
await BlockService().unblockNumber(phoneNumber);
if (mounted) {
@ -80,30 +82,12 @@ class _ContactModalState extends State<ContactModal> {
if (phoneNumber != 'No phone number' && mounted) {
_checkIfBlocked();
}
if (mounted) {
Navigator.of(context).pop();
}
}
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)) {
@ -246,7 +230,8 @@ class _ContactModalState extends State<ContactModal> {
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
widget.contact.thumbnail != null && widget.contact.thumbnail!.isNotEmpty
widget.contact.thumbnail != null &&
widget.contact.thumbnail!.isNotEmpty
? ClipOval(
child: Image.memory(
widget.contact.thumbnail!,
@ -260,7 +245,8 @@ class _ContactModalState extends State<ContactModal> {
radius: 50,
child: Text(
widget.contact.displayName.isNotEmpty
? widget.contact.displayName[0].toUpperCase()
? widget.contact.displayName[0]
.toUpperCase()
: '?',
style: TextStyle(
color: darken(avatarColor),
@ -287,7 +273,8 @@ class _ContactModalState extends State<ContactModal> {
child: Column(
children: [
ListTile(
leading: const Icon(Icons.phone, color: Colors.green),
leading:
const Icon(Icons.phone, color: Colors.green),
title: Text(
_obfuscateService.obfuscateData(phoneNumber),
style: const TextStyle(color: Colors.white),
@ -300,19 +287,21 @@ class _ContactModalState extends State<ContactModal> {
},
),
ListTile(
leading: const Icon(Icons.message, color: Colors.blue),
leading:
const Icon(Icons.message, color: Colors.blue),
title: Text(
_obfuscateService.obfuscateData(phoneNumber),
style: const TextStyle(color: Colors.white),
),
onTap: () {
if (widget.contact.phones.isNotEmpty) {
_launchSms(phoneNumber);
_messageService.sendSms(phoneNumber);
}
},
),
ListTile(
leading: const Icon(Icons.email, color: Colors.orange),
leading:
const Icon(Icons.email, color: Colors.orange),
title: Text(
email,
style: const TextStyle(color: Colors.white),
@ -326,7 +315,8 @@ class _ContactModalState extends State<ContactModal> {
const Divider(color: Colors.grey),
// Favorite, Edit, and Block/Unblock Buttons
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
padding:
const EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
children: [
// Favorite button
@ -342,8 +332,9 @@ class _ContactModalState extends State<ContactModal> {
icon: Icon(widget.isFavorite
? Icons.star
: Icons.star_border),
label: Text(
widget.isFavorite ? 'Unfavorite' : 'Favorite'),
label: Text(widget.isFavorite
? 'Unfavorite'
: 'Favorite'),
),
),
const SizedBox(height: 10),
@ -362,9 +353,11 @@ class _ContactModalState extends State<ContactModal> {
width: double.infinity,
child: ElevatedButton.icon(
onPressed: _toggleBlockState,
icon: Icon(
isBlocked ? Icons.block : Icons.block_flipped),
label: Text(isBlocked ? 'Unblock' : 'Block'),
icon: Icon(isBlocked
? Icons.block
: Icons.block_flipped),
label:
Text(isBlocked ? 'Unblock' : 'Block'),
),
),
],