refactor: update imports and restructure widget files for better organization
This commit is contained in:
parent
afa0c5b5a4
commit
d7ed797b80
@ -4,7 +4,7 @@ import '../../presentation/features/call/incoming_call_page.dart';
|
|||||||
import '../../presentation/features/home/home_page.dart';
|
import '../../presentation/features/home/home_page.dart';
|
||||||
import '../../presentation/features/settings/settings.dart'; // Updated import
|
import '../../presentation/features/settings/settings.dart'; // Updated import
|
||||||
import '../../presentation/features/contacts/contact_page.dart';
|
import '../../presentation/features/contacts/contact_page.dart';
|
||||||
import '../../presentation/features/dialer/composition_page.dart';
|
import '../../presentation/features/composition/composition.dart';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
class AppRouter {
|
class AppRouter {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// lib/services/obfuscate_service.dart
|
// lib/services/obfuscate_service.dart
|
||||||
import 'package:dialer/widgets/color_darkener.dart';
|
import 'package:dialer/presentation/common/widgets/color_darkener.dart';
|
||||||
|
|
||||||
import '../../core/config/app_config.dart';
|
import '../../core/config/app_config.dart';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
@ -4,7 +4,6 @@ import 'package:url_launcher/url_launcher.dart';
|
|||||||
import '../../../domain/services/contact_service.dart';
|
import '../../../domain/services/contact_service.dart';
|
||||||
import '../../../domain/services/obfuscate_service.dart';
|
import '../../../domain/services/obfuscate_service.dart';
|
||||||
import '../../../domain/services/call_service.dart';
|
import '../../../domain/services/call_service.dart';
|
||||||
import '../contacts/widgets/add_contact_button.dart';
|
|
||||||
|
|
||||||
class CompositionPage extends StatefulWidget {
|
class CompositionPage extends StatefulWidget {
|
||||||
const CompositionPage({super.key});
|
const CompositionPage({super.key});
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_contacts/flutter_contacts.dart';
|
import 'package:flutter_contacts/flutter_contacts.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import '../../../../widgets/username_color_generator.dart';
|
import '../../../common/widgets/username_color_generator.dart';
|
||||||
import '../../../../widgets/color_darkener.dart';
|
import '../../../common/widgets/color_darkener.dart';
|
||||||
import '../../../../domain/services/obfuscate_service.dart';
|
import '../../../../domain/services/obfuscate_service.dart';
|
||||||
import '../../../../domain/services/block_service.dart';
|
import '../../../../domain/services/block_service.dart';
|
||||||
import '../../../../domain/services/contact_service.dart';
|
import '../../../../domain/services/contact_service.dart';
|
||||||
@ -86,15 +86,6 @@ class _ContactModalState extends State<ContactModal> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
void _launchSms(String phoneNumber) async {
|
||||||
final uri = Uri(scheme: 'sms', path: phoneNumber);
|
final uri = Uri(scheme: 'sms', path: phoneNumber);
|
||||||
if (await canLaunchUrl(uri)) {
|
if (await canLaunchUrl(uri)) {
|
||||||
|
@ -1,311 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_contacts/flutter_contacts.dart';
|
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
import '../../../domain/services/contact_service.dart';
|
|
||||||
import '../../../domain/services/obfuscate_service.dart';
|
|
||||||
import '../../../domain/services/call_service.dart';
|
|
||||||
import '../contacts/widgets/add_contact_button.dart';
|
|
||||||
|
|
||||||
class CompositionPage extends StatefulWidget {
|
|
||||||
const CompositionPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_CompositionPageState createState() => _CompositionPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CompositionPageState extends State<CompositionPage> {
|
|
||||||
String dialedNumber = "";
|
|
||||||
List<Contact> _allContacts = [];
|
|
||||||
List<Contact> _filteredContacts = [];
|
|
||||||
final ContactService _contactService = ContactService();
|
|
||||||
final ObfuscateService _obfuscateService = ObfuscateService();
|
|
||||||
final CallService _callService = CallService();
|
|
||||||
|
|
||||||
// Cache for normalized phone numbers to avoid repeated processing
|
|
||||||
final Map<String, String> _normalizedPhoneCache = {};
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_fetchContacts();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _fetchContacts() async {
|
|
||||||
_allContacts = await _contactService.fetchContacts();
|
|
||||||
_filteredContacts = _allContacts;
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
String _getNormalizedPhone(String phone) {
|
|
||||||
return _normalizedPhoneCache.putIfAbsent(
|
|
||||||
phone,
|
|
||||||
() => phone.replaceAll(RegExp(r'\D'), '')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _filterContacts() {
|
|
||||||
if (dialedNumber.isEmpty) {
|
|
||||||
setState(() {
|
|
||||||
_filteredContacts = _allContacts;
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String normalizedDialed = dialedNumber.replaceAll(RegExp(r'\D'), '');
|
|
||||||
final String lowerDialed = dialedNumber.toLowerCase();
|
|
||||||
|
|
||||||
setState(() {
|
|
||||||
_filteredContacts = _allContacts.where((contact) {
|
|
||||||
// Check phone numbers
|
|
||||||
final phoneMatch = contact.phones.any((phone) =>
|
|
||||||
_getNormalizedPhone(phone.number).contains(normalizedDialed));
|
|
||||||
|
|
||||||
// Only check name if phone doesn't match (optimization)
|
|
||||||
if (phoneMatch) return true;
|
|
||||||
|
|
||||||
// Check display name
|
|
||||||
return contact.displayName.toLowerCase().contains(lowerDialed);
|
|
||||||
}).toList();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onNumberPress(String number) {
|
|
||||||
setState(() {
|
|
||||||
dialedNumber += number;
|
|
||||||
_filterContacts();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onDeletePress() {
|
|
||||||
setState(() {
|
|
||||||
if (dialedNumber.isNotEmpty) {
|
|
||||||
dialedNumber = dialedNumber.substring(0, dialedNumber.length - 1);
|
|
||||||
_filterContacts();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onClearPress() {
|
|
||||||
setState(() {
|
|
||||||
dialedNumber = "";
|
|
||||||
_filteredContacts = _allContacts;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void _makeCall(String phoneNumber) async {
|
|
||||||
try {
|
|
||||||
await _callService.makeGsmCall(context, phoneNumber: phoneNumber);
|
|
||||||
setState(() {
|
|
||||||
dialedNumber = phoneNumber;
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint("Error making call: $e");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _launchSms(String phoneNumber) async {
|
|
||||||
final uri = Uri(scheme: 'sms', path: phoneNumber);
|
|
||||||
if (await canLaunchUrl(uri)) {
|
|
||||||
await launchUrl(uri);
|
|
||||||
} else {
|
|
||||||
debugPrint('Could not send SMS to $phoneNumber');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: Colors.black,
|
|
||||||
body: Stack(
|
|
||||||
children: [
|
|
||||||
Column(
|
|
||||||
children: [
|
|
||||||
// Top half: Display contacts matching dialed number
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.only(
|
|
||||||
top: 42.0, left: 16.0, right: 16.0, bottom: 16.0),
|
|
||||||
color: Colors.black,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: ListView(
|
|
||||||
children: _filteredContacts.isNotEmpty
|
|
||||||
? _filteredContacts.map((contact) {
|
|
||||||
final phoneNumber = contact.phones.isNotEmpty
|
|
||||||
? contact.phones.first.number
|
|
||||||
: 'No phone number';
|
|
||||||
return ListTile(
|
|
||||||
title: Text(
|
|
||||||
_obfuscateService.obfuscateData(contact.displayName),
|
|
||||||
style: const TextStyle(color: Colors.white),
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
_obfuscateService.obfuscateData(phoneNumber),
|
|
||||||
style: const TextStyle(color: Colors.grey),
|
|
||||||
),
|
|
||||||
trailing: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.phone,
|
|
||||||
color: Colors.green[300],
|
|
||||||
size: 20),
|
|
||||||
onPressed: () {
|
|
||||||
_makeCall(phoneNumber);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
icon: Icon(Icons.message,
|
|
||||||
color: Colors.blue[300],
|
|
||||||
size: 20),
|
|
||||||
onPressed: () {
|
|
||||||
_launchSms(phoneNumber);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
// Handle contact selection if needed
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}).toList()
|
|
||||||
: [],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Bottom half: Dialpad and Dialed number display with erase button
|
|
||||||
Expanded(
|
|
||||||
flex: 2,
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
// Display dialed number with erase button
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Align(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Text(
|
|
||||||
dialedNumber,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 24, color: Colors.white),
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
onPressed: _onClearPress,
|
|
||||||
icon: const Icon(Icons.backspace,
|
|
||||||
color: Colors.white),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
|
|
||||||
// Dialpad
|
|
||||||
Expanded(
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
_buildDialButton('1'),
|
|
||||||
_buildDialButton('2'),
|
|
||||||
_buildDialButton('3'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
_buildDialButton('4'),
|
|
||||||
_buildDialButton('5'),
|
|
||||||
_buildDialButton('6'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
_buildDialButton('7'),
|
|
||||||
_buildDialButton('8'),
|
|
||||||
_buildDialButton('9'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment:
|
|
||||||
MainAxisAlignment.spaceEvenly,
|
|
||||||
children: [
|
|
||||||
_buildDialButton('*'),
|
|
||||||
_buildDialButton('0'),
|
|
||||||
_buildDialButton('#'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
// Add Contact Button
|
|
||||||
Positioned(
|
|
||||||
bottom: 20.0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: Center(
|
|
||||||
child: AddContactButton(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Top Row with Back Arrow
|
|
||||||
Positioned(
|
|
||||||
top: 40.0,
|
|
||||||
left: 16.0,
|
|
||||||
child: IconButton(
|
|
||||||
icon: const Icon(Icons.arrow_back, color: Colors.white),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildDialButton(String number) {
|
|
||||||
return ElevatedButton(
|
|
||||||
onPressed: () => _onNumberPress(number),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: Colors.black,
|
|
||||||
shape: const CircleBorder(),
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
number,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 24,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,8 +6,8 @@ import 'package:intl/intl.dart';
|
|||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import '../../../domain/services/obfuscate_service.dart';
|
import '../../../domain/services/obfuscate_service.dart';
|
||||||
import '../../../widgets/color_darkener.dart';
|
import '../../common/widgets/color_darkener.dart';
|
||||||
import '../../../widgets/username_color_generator.dart';
|
import '../../common/widgets/username_color_generator.dart';
|
||||||
import '../../../domain/services/block_service.dart';
|
import '../../../domain/services/block_service.dart';
|
||||||
import '../../../domain/services/call_service.dart';
|
import '../../../domain/services/call_service.dart';
|
||||||
import '../contacts/contact_state.dart';
|
import '../contacts/contact_state.dart';
|
||||||
|
@ -3,7 +3,7 @@ import '../../../domain/services/obfuscate_service.dart';
|
|||||||
import '../contacts/contact_page.dart';
|
import '../contacts/contact_page.dart';
|
||||||
import '../favorites/favorites_page.dart';
|
import '../favorites/favorites_page.dart';
|
||||||
import '../history/history_page.dart';
|
import '../history/history_page.dart';
|
||||||
import '../dialer/composition_page.dart';
|
import '../composition/composition.dart';
|
||||||
import '../settings/settings.dart';
|
import '../settings/settings.dart';
|
||||||
import '../voicemail/voicemail_page.dart';
|
import '../voicemail/voicemail_page.dart';
|
||||||
import '../contacts/contact_state.dart';
|
import '../contacts/contact_state.dart';
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class LoadingIndicatorWidget extends StatelessWidget {
|
|
||||||
const LoadingIndicatorWidget({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const Center(child: CircularProgressIndicator());
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user