feat: contact info in ongoing and incoming call
All checks were successful
/ mirror (push) Successful in 5s
/ build (push) Successful in 9m56s
/ build-stealth (push) Successful in 9m58s

This commit is contained in:
Florian Griffon 2025-04-18 23:05:55 +03:00
parent f6559f8a93
commit 5bb64d98b8

View File

@ -8,7 +8,7 @@ import '../services/contact_service.dart';
class CallService {
static const MethodChannel _channel = MethodChannel('call_service');
static String? currentPhoneNumber;
static String? currentDisplayName;
static String? currentDisplayName;
static Uint8List? currentThumbnail;
static bool _isCallPageVisible = false;
static Map<String, dynamic>? _pendingCall;
@ -19,31 +19,29 @@ class CallService {
final _callStateController = StreamController<String>.broadcast();
static final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
Stream<String> get callStateStream => _callStateController.stream;
CallService() {
_channel.setMethodCallHandler((call) async {
final eventTime = DateTime.now().millisecondsSinceEpoch;
final disconnectCause = call.arguments["disconnectCause"] ?? "none";
print('CallService: [${eventTime}ms] Handling method call: ${call.method} with args: ${call.arguments}, disconnectCause: $disconnectCause');
print('CallService: Handling method call: ${call.method}, with args: ${call.arguments}');
switch (call.method) {
case "callAdded":
final phoneNumber = call.arguments["callId"] as String?;
final state = call.arguments["state"] as String?;
if (phoneNumber == null || state == null) {
print('CallService: [${eventTime}ms] Invalid callAdded args: $call.arguments');
print('CallService: Invalid callAdded args: $call.arguments');
return;
}
final decodedPhoneNumber = Uri.decodeComponent(phoneNumber.replaceFirst('tel:', ''));
print('CallService: [${eventTime}ms] Decoded phone number: $decodedPhoneNumber');
print('CallService: Decoded phone number: $decodedPhoneNumber');
if (_activeCallNumber != decodedPhoneNumber) {
currentPhoneNumber = decodedPhoneNumber;
if (currentDisplayName == null || currentDisplayName == currentPhoneNumber) {
await _fetchContactInfo(decodedPhoneNumber);
}
}
print('CallService: [${eventTime}ms] Call added, number: $currentPhoneNumber, displayName: $currentDisplayName, state: $state');
print('CallService: Call added, number: $currentPhoneNumber, displayName: $currentDisplayName, state: $state');
_callStateController.add(state);
if (state == "ringing") {
_handleIncomingCall(decodedPhoneNumber);
@ -55,16 +53,13 @@ class CallService {
final state = call.arguments["state"] as String?;
wasPhoneLocked = call.arguments["wasPhoneLocked"] as bool? ?? false;
if (state == null) {
print('CallService: [${eventTime}ms] Invalid callStateChanged args: $call.arguments');
print('CallService: Invalid callStateChanged args: $call.arguments');
return;
}
print('CallService: [${eventTime}ms] State changed to $state, wasPhoneLocked: $wasPhoneLocked, disconnectCause: $disconnectCause');
print('CallService: State changed to $state, wasPhoneLocked: $wasPhoneLocked');
_callStateController.add(state);
if (state == "disconnected" || state == "disconnecting") {
final closeStart = DateTime.now().millisecondsSinceEpoch;
print('CallService: [${closeStart}ms] Initiating closeCallPage for state: $state');
_closeCallPage();
print('CallService: [${DateTime.now().millisecondsSinceEpoch}ms] closeCallPage completed');
if (wasPhoneLocked) {
await _channel.invokeMethod("callEndedFromFlutter");
}
@ -81,13 +76,13 @@ class CallService {
await _fetchContactInfo(currentPhoneNumber!);
}
} else {
print('CallService: [${eventTime}ms] Skipping fetch, active call: $_activeCallNumber, current: $currentPhoneNumber, displayName: $currentDisplayName');
print('CallService: Skipping fetch, active call: $_activeCallNumber, current: $currentPhoneNumber, displayName: $currentDisplayName');
}
_navigateToCallPage();
} else if (state == "ringing") {
final phoneNumber = call.arguments["callId"] as String?;
if (phoneNumber == null) {
print('CallService: [${eventTime}ms] Invalid ringing callId: $call.arguments');
print('CallService: Invalid ringing callId: $call.arguments');
return;
}
final decodedPhoneNumber = Uri.decodeComponent(phoneNumber.replaceFirst('tel:', ''));
@ -103,12 +98,8 @@ class CallService {
case "callEnded":
case "callRemoved":
wasPhoneLocked = call.arguments["wasPhoneLocked"] as bool? ?? false;
print('CallService: [${eventTime}ms] Call ended/removed, wasPhoneLocked: $wasPhoneLocked, disconnectCause: $disconnectCause');
_callStateController.add("disconnected");
final closeStart = DateTime.now().millisecondsSinceEpoch;
print('CallService: [${closeStart}ms] Initiating closeCallPage for callEnded/callRemoved');
print('CallService: Call ended/removed, wasPhoneLocked: $wasPhoneLocked');
_closeCallPage();
print('CallService: [${DateTime.now().millisecondsSinceEpoch}ms] closeCallPage completed');
if (wasPhoneLocked) {
await _channel.invokeMethod("callEndedFromFlutter");
}
@ -121,7 +112,7 @@ class CallService {
final phoneNumber = call.arguments["phoneNumber"] as String?;
wasPhoneLocked = call.arguments["wasPhoneLocked"] as bool? ?? false;
if (phoneNumber == null) {
print('CallService: [${eventTime}ms] Invalid incomingCallFromNotification args: $call.arguments');
print('CallService: Invalid incomingCallFromNotification args: $call.arguments');
return;
}
final decodedPhoneNumber = Uri.decodeComponent(phoneNumber);
@ -131,12 +122,12 @@ class CallService {
await _fetchContactInfo(decodedPhoneNumber);
}
}
print('CallService: [${eventTime}ms] Incoming call from notification: $decodedPhoneNumber, displayName: $currentDisplayName, wasPhoneLocked: $wasPhoneLocked');
print('CallService: Incoming call from notification: $decodedPhoneNumber, displayName: $currentDisplayName, wasPhoneLocked: $wasPhoneLocked');
_handleIncomingCall(decodedPhoneNumber);
break;
case "audioStateChanged":
final route = call.arguments["route"] as int?;
print('CallService: [${eventTime}ms] Audio state changed, route: $route');
print('CallService: Audio state changed, route: $route');
break;
}
});
@ -320,18 +311,18 @@ class CallService {
print('CallService: Cannot close page, context is null');
return;
}
final currentRoute = ModalRoute.of(context)?.settings.name ?? 'unknown';
print('CallService: Closing call page, _isCallPageVisible: $_isCallPageVisible, Current Route: $currentRoute');
if (_isCallPageVisible && (currentRoute == '/call' || currentRoute == '/incoming_call')) {
print('CallService: Closing call page, _isCallPageVisible: $_isCallPageVisible');
if (Navigator.canPop(context)) {
print('CallService: Popping call page');
Navigator.pop(context);
_isCallPageVisible = false;
} else {
print('CallService: No call page to pop, _isCallPageVisible: $_isCallPageVisible, Current Route: $currentRoute');
print('CallService: No page to pop');
}
_isCallPageVisible = false;
_activeCallNumber = null;
}
Future<Map<String, dynamic>> makeGsmCall(
BuildContext context, {
required String phoneNumber,
@ -368,19 +359,13 @@ class CallService {
}
}
Future<Map<String, dynamic>> hangUpCall(BuildContext context) async {
Future<Map<String, dynamic>> hangUpCall(BuildContext context) async {
try {
print('CallService: Hanging up call');
final result = await _channel.invokeMethod('hangUpCall');
print('CallService: hangUpCall result: $result');
final resultMap = Map<String, dynamic>.from(result as Map);
if (resultMap["status"] == "ended") {
final closeStart = DateTime.now().millisecondsSinceEpoch;
print('CallService: [${closeStart}ms] Initiating closeCallPage for hangUpCall');
_closeCallPage();
print('CallService: [${DateTime.now().millisecondsSinceEpoch}ms] closeCallPage completed');
} else {
print('CallService: Hang up failed, status: ${resultMap["status"]}');
if (resultMap["status"] != "ended") {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Failed to end call")),
);
@ -391,7 +376,6 @@ class CallService {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Error hanging up call: $e")),
);
_closeCallPage();
return {"status": "error", "message": e.toString()};
}
}