feat: enhance SIM management with state tracking and UI updates

This commit is contained in:
AlexisDanlos 2025-06-18 18:31:13 +02:00 committed by stcb
parent c8ea9204ff
commit 71485a4346
2 changed files with 92 additions and 21 deletions

View File

@ -11,6 +11,7 @@ class CallService {
static String? currentPhoneNumber;
static String? currentDisplayName;
static Uint8List? currentThumbnail;
static int? currentSimSlot; // Track which SIM slot is being used
static bool _isCallPageVisible = false;
static Map<String, dynamic>? _pendingCall;
static bool wasPhoneLocked = false;
@ -20,15 +21,38 @@ class CallService {
final _callStateController = StreamController<String>.broadcast();
final _audioStateController =
StreamController<Map<String, dynamic>>.broadcast();
final _simStateController = StreamController<int?>.broadcast();
Map<String, dynamic>? _currentAudioState;
static final GlobalKey<NavigatorState> navigatorKey =
GlobalKey<NavigatorState>();
Stream<String> get callStateStream => _callStateController.stream;
Stream<Map<String, dynamic>> get audioStateStream =>
_audioStateController.stream;
Stream<int?> get simStateStream => _simStateController.stream;
Map<String, dynamic>? get currentAudioState => _currentAudioState;
// Getter for current SIM slot
static int? get getCurrentSimSlot => currentSimSlot;
// Get SIM display name for the current call
static String? getCurrentSimDisplayName() {
if (currentSimSlot == null) return null;
return "SIM ${currentSimSlot! + 1}";
}
// Cancel pending SIM switch (used when user manually hangs up)
void cancelPendingSimSwitch() {
if (_pendingSimSwitch != null) {
print('CallService: Canceling pending SIM switch due to manual hangup');
_pendingSimSwitch = null;
_manualHangupFlag = true; // Mark that hangup was manual
print('CallService: Manual hangup flag set to $_manualHangupFlag');
} else {
print(
'CallService: No pending SIM switch to cancel, but setting manual hangup flag');
_manualHangupFlag =
true; // Still mark as manual even if no pending switch
}
}
CallService() {
_channel.setMethodCallHandler((call) async {
@ -73,9 +97,15 @@ class CallService {
'CallService: State changed to $state, wasPhoneLocked: $wasPhoneLocked');
_callStateController.add(state);
if (state == "disconnected" || state == "disconnecting") {
// Only close call page if there's no pending SIM switch
if (_pendingSimSwitch == null) {
// Close call page if no pending SIM switch OR if it was a manual hangup
if (_pendingSimSwitch == null || _manualHangupFlag) {
_closeCallPage();
// Only reset manual hangup flag after successful page close
if (_manualHangupFlag) {
print(
'CallService: Resetting manual hangup flag after page close');
_manualHangupFlag = false;
}
}
if (wasPhoneLocked) {
await _channel.invokeMethod("callEndedFromFlutter");
@ -127,9 +157,8 @@ class CallService {
case "callRemoved":
wasPhoneLocked = call.arguments["wasPhoneLocked"] as bool? ?? false;
print(
'CallService: Call ended/removed, wasPhoneLocked: $wasPhoneLocked');
// Only close call page if there's no pending SIM switch
if (_pendingSimSwitch == null) {
'CallService: Call ended/removed, wasPhoneLocked: $wasPhoneLocked'); // Only close call page if there's no pending SIM switch AND no manual hangup in progress
if (_pendingSimSwitch == null && !_manualHangupFlag) {
_closeCallPage();
}
if (wasPhoneLocked) {
@ -138,6 +167,8 @@ class CallService {
currentPhoneNumber = null;
currentDisplayName = null;
currentThumbnail = null;
currentSimSlot = null; // Reset SIM slot when call ends
_simStateController.add(null); // Notify UI that SIM is cleared
_activeCallNumber = null;
break;
case "incomingCallFromNotification":
@ -493,6 +524,8 @@ class CallService {
currentPhoneNumber = phoneNumber;
currentDisplayName = displayName ?? phoneNumber;
currentThumbnail = thumbnail;
currentSimSlot = simSlot; // Track the SIM slot being used
_simStateController.add(simSlot); // Notify UI of SIM change
if (displayName == null || thumbnail == null) {
await _fetchContactInfo(phoneNumber);
}
@ -519,6 +552,7 @@ class CallService {
// Pending SIM switch data
static Map<String, dynamic>? _pendingSimSwitch;
static bool _manualHangupFlag = false; // Track if hangup was manual
// Getter to check if there's a pending SIM switch
static bool get hasPendingSimSwitch => _pendingSimSwitch != null;
@ -583,13 +617,15 @@ class CallService {
print('CallService: Executing pending SIM switch redial');
// Wait a moment to ensure the previous call is fully disconnected
await Future.delayed(const Duration(milliseconds: 1000));
// Store the new call info for the redial
await Future.delayed(const Duration(
milliseconds: 1000)); // Store the new call info for the redial
currentPhoneNumber = switchData['phoneNumber'];
currentDisplayName = switchData['displayName'];
currentThumbnail =
switchData['thumbnail']; // Make the new call with the selected SIM
currentThumbnail = switchData['thumbnail'];
currentSimSlot = switchData['simSlot']; // Track the new SIM slot
_simStateController.add(switchData['simSlot']); // Notify UI of SIM change
// Make the new call with the selected SIM
final result = await _channel.invokeMethod('makeGsmCall', {
'phoneNumber': switchData['phoneNumber'],
'simSlot': switchData['simSlot'],

View File

@ -36,6 +36,7 @@ class _CallPageState extends State<CallPage> {
String _callStatus = "Calling...";
StreamSubscription<String>? _callStateSubscription;
StreamSubscription<Map<String, dynamic>>? _audioStateSubscription;
StreamSubscription<int?>? _simStateSubscription;
bool _isCallActive = true; // Track if call is still active
bool get isNumberUnknown => widget.displayName == widget.phoneNumber;
@ -46,6 +47,7 @@ class _CallPageState extends State<CallPage> {
_checkInitialCallState();
_listenToCallState();
_listenToAudioState();
_listenToSimState();
_setInitialAudioState();
}
@ -54,6 +56,7 @@ class _CallPageState extends State<CallPage> {
_callTimer?.cancel();
_callStateSubscription?.cancel();
_audioStateSubscription?.cancel();
_simStateSubscription?.cancel();
super.dispose();
}
@ -103,15 +106,8 @@ class _CallPageState extends State<CallPage> {
} else if (state == "disconnected" || state == "disconnecting") {
_callTimer?.cancel();
_callStatus = "Call Ended";
_isCallActive =
false; // Only navigate back if there's no pending SIM switch
if (!CallService.hasPendingSimSwitch) {
Future.delayed(const Duration(seconds: 2), () {
if (mounted && Navigator.canPop(context)) {
Navigator.of(context).pop();
}
});
}
_isCallActive = false;
// Let CallService handle navigation - don't navigate from here
} else {
_callStatus = "Calling...";
_isCallActive = true;
@ -132,6 +128,17 @@ class _CallPageState extends State<CallPage> {
});
}
void _listenToSimState() {
_simStateSubscription = _callService.simStateStream.listen((simSlot) {
if (mounted) {
setState(() {
// UI will update automatically because we're listening to the stream
// The SIM display will show the new SIM slot
});
}
});
}
void _startCallTimer() {
_callTimer?.cancel();
_callTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
@ -274,7 +281,12 @@ class _CallPageState extends State<CallPage> {
}
try {
print('CallPage: Initiating hangUp');
print(
'CallPage: Initiating manual hangUp - canceling any pending SIM switch');
// Cancel any pending SIM switch since user is manually hanging up
_callService.cancelPendingSimSwitch();
final result = await _callService.hangUpCall(context);
print('CallPage: Hang up result: $result');
} catch (e) {
@ -386,6 +398,29 @@ class _CallPageState extends State<CallPage> {
color: Colors.white70,
),
),
// Show SIM information if available
if (CallService.getCurrentSimDisplayName() != null)
Container(
margin: const EdgeInsets.only(top: 4.0),
padding: const EdgeInsets.symmetric(
horizontal: 8.0, vertical: 2.0),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: Colors.blue.withOpacity(0.5),
width: 1,
),
),
child: Text(
CallService.getCurrentSimDisplayName()!,
style: TextStyle(
fontSize: statusFontSize - 2,
color: Colors.lightBlueAccent,
fontWeight: FontWeight.w500,
),
),
),
],
),
),