feat: enhance SIM management with state tracking and UI updates
This commit is contained in:
parent
c8ea9204ff
commit
71485a4346
@ -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'],
|
||||||
|
@ -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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Loading…
Reference in New Issue
Block a user