101 lines
2.5 KiB
Dart
101 lines
2.5 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
import 'package:call_log/call_log.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
|
|
class OtpController {
|
|
DateTime? _startTime;
|
|
Timer? _pollTimer;
|
|
String? _detectedOtp;
|
|
bool _isPolling = false;
|
|
|
|
// Callbacks
|
|
Function(String status)? onStatusChanged;
|
|
Function(String otp)? onOtpDetected;
|
|
Function()? onTimeout;
|
|
|
|
/// Start polling call log for missed calls
|
|
Future<bool> startWaiting(String phone) async {
|
|
if (Platform.isIOS) {
|
|
// iOS: cannot read call log, skip to manual entry
|
|
onStatusChanged?.call('manual_ios');
|
|
return false;
|
|
}
|
|
|
|
// Request phone permissions (usually covers call log on many Android versions)
|
|
var status = await Permission.phone.request();
|
|
|
|
if (!status.isGranted) {
|
|
onStatusChanged?.call('permission_denied');
|
|
return false;
|
|
}
|
|
|
|
_startTime = DateTime.now();
|
|
_isPolling = true;
|
|
onStatusChanged?.call('waiting');
|
|
|
|
// Poll every 1.5 seconds
|
|
_pollTimer = Timer.periodic(const Duration(milliseconds: 1500), (_) {
|
|
_checkCallLog(phone);
|
|
});
|
|
|
|
// Timeout after 120 seconds
|
|
Future.delayed(const Duration(seconds: 120), () {
|
|
if (_isPolling && _detectedOtp == null) {
|
|
stopWaiting();
|
|
onTimeout?.call();
|
|
}
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Check call log for missed calls since _startTime
|
|
Future<void> _checkCallLog(String phone) async {
|
|
try {
|
|
final Iterable<CallLogEntry> entries = await CallLog.query(
|
|
dateFrom: _startTime!.millisecondsSinceEpoch,
|
|
);
|
|
|
|
for (var entry in entries) {
|
|
if (entry.callType == CallType.missed && entry.number != null) {
|
|
final otp = extractOTP(entry.number!);
|
|
if (otp.length == 4) {
|
|
_detectedOtp = otp;
|
|
stopWaiting();
|
|
onStatusChanged?.call('call_detected');
|
|
onOtpDetected?.call(otp);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
// Silently continue polling
|
|
}
|
|
}
|
|
|
|
/// Extract OTP from caller number (last 4 digits)
|
|
String extractOTP(String callerNumber) {
|
|
final digitsOnly = callerNumber.replaceAll(RegExp(r'[^\d]'), '');
|
|
if (digitsOnly.length >= 4) {
|
|
return digitsOnly.substring(digitsOnly.length - 4);
|
|
}
|
|
return digitsOnly;
|
|
}
|
|
|
|
/// Stop polling
|
|
void stopWaiting() {
|
|
_isPolling = false;
|
|
_pollTimer?.cancel();
|
|
_pollTimer = null;
|
|
}
|
|
|
|
/// Dispose resources
|
|
void dispose() {
|
|
stopWaiting();
|
|
onStatusChanged = null;
|
|
onOtpDetected = null;
|
|
onTimeout = null;
|
|
}
|
|
}
|