feat: enhance SIM management with state tracking and UI updates
Some checks failed
/ mirror (push) Failing after 5s
/ build-stealth (push) Successful in 10m33s
/ build (push) Successful in 10m31s

This commit is contained in:
AlexisDanlos 2025-06-18 18:31:13 +02:00
parent 4eff7b503c
commit 4b4604448d
2 changed files with 92 additions and 21 deletions

View File

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

View File

@ -36,6 +36,7 @@ class _CallPageState extends State<CallPage> {
String _callStatus = "Calling..."; String _callStatus = "Calling...";
StreamSubscription<String>? _callStateSubscription; StreamSubscription<String>? _callStateSubscription;
StreamSubscription<Map<String, dynamic>>? _audioStateSubscription; StreamSubscription<Map<String, dynamic>>? _audioStateSubscription;
StreamSubscription<int?>? _simStateSubscription;
bool _isCallActive = true; // Track if call is still active bool _isCallActive = true; // Track if call is still active
bool get isNumberUnknown => widget.displayName == widget.phoneNumber; bool get isNumberUnknown => widget.displayName == widget.phoneNumber;
@ -46,6 +47,7 @@ class _CallPageState extends State<CallPage> {
_checkInitialCallState(); _checkInitialCallState();
_listenToCallState(); _listenToCallState();
_listenToAudioState(); _listenToAudioState();
_listenToSimState();
_setInitialAudioState(); _setInitialAudioState();
} }
@ -54,6 +56,7 @@ class _CallPageState extends State<CallPage> {
_callTimer?.cancel(); _callTimer?.cancel();
_callStateSubscription?.cancel(); _callStateSubscription?.cancel();
_audioStateSubscription?.cancel(); _audioStateSubscription?.cancel();
_simStateSubscription?.cancel();
super.dispose(); super.dispose();
} }
@ -103,15 +106,8 @@ class _CallPageState extends State<CallPage> {
} else if (state == "disconnected" || state == "disconnecting") { } else if (state == "disconnected" || state == "disconnecting") {
_callTimer?.cancel(); _callTimer?.cancel();
_callStatus = "Call Ended"; _callStatus = "Call Ended";
_isCallActive = _isCallActive = false;
false; // Only navigate back if there's no pending SIM switch // Let CallService handle navigation - don't navigate from here
if (!CallService.hasPendingSimSwitch) {
Future.delayed(const Duration(seconds: 2), () {
if (mounted && Navigator.canPop(context)) {
Navigator.of(context).pop();
}
});
}
} else { } else {
_callStatus = "Calling..."; _callStatus = "Calling...";
_isCallActive = true; _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() { void _startCallTimer() {
_callTimer?.cancel(); _callTimer?.cancel();
_callTimer = Timer.periodic(const Duration(seconds: 1), (timer) { _callTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
@ -274,7 +281,12 @@ class _CallPageState extends State<CallPage> {
} }
try { 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); final result = await _callService.hangUpCall(context);
print('CallPage: Hang up result: $result'); print('CallPage: Hang up result: $result');
} catch (e) { } catch (e) {
@ -386,6 +398,29 @@ class _CallPageState extends State<CallPage> {
color: Colors.white70, 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,
),
),
),
], ],
), ),
), ),