Add TWP Softphone Flutter app and complete mobile backend API
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for
mobile VoIP, implement unhold_call() with call leg detection, wire FCM
push notifications into call queue and webhook missed call handlers,
add data-only FCM message support for Android background wake, and add
Twilio API Key / Push Credential settings fields.
Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth
with auto-refresh, SSE real-time queue updates, FCM push notifications,
Material 3 UI with dashboard, active call screen, dialpad, and call
controls (mute/speaker/hold/transfer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:01:23 -08:00
|
|
|
import 'dart:async';
|
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
|
import '../models/agent_status.dart';
|
|
|
|
|
import '../models/queue_state.dart';
|
|
|
|
|
import '../services/api_client.dart';
|
|
|
|
|
import '../services/sse_service.dart';
|
|
|
|
|
|
2026-03-06 18:05:54 -08:00
|
|
|
class PhoneNumber {
|
|
|
|
|
final String phoneNumber;
|
|
|
|
|
final String friendlyName;
|
|
|
|
|
PhoneNumber({required this.phoneNumber, required this.friendlyName});
|
|
|
|
|
factory PhoneNumber.fromJson(Map<String, dynamic> json) => PhoneNumber(
|
|
|
|
|
phoneNumber: json['phone_number'] as String,
|
|
|
|
|
friendlyName: json['friendly_name'] as String,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
Add TWP Softphone Flutter app and complete mobile backend API
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for
mobile VoIP, implement unhold_call() with call leg detection, wire FCM
push notifications into call queue and webhook missed call handlers,
add data-only FCM message support for Android background wake, and add
Twilio API Key / Push Credential settings fields.
Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth
with auto-refresh, SSE real-time queue updates, FCM push notifications,
Material 3 UI with dashboard, active call screen, dialpad, and call
controls (mute/speaker/hold/transfer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:01:23 -08:00
|
|
|
class AgentProvider extends ChangeNotifier {
|
|
|
|
|
final ApiClient _api;
|
|
|
|
|
final SseService _sse;
|
|
|
|
|
|
|
|
|
|
AgentStatus? _status;
|
|
|
|
|
List<QueueInfo> _queues = [];
|
|
|
|
|
bool _sseConnected = false;
|
2026-03-06 18:05:54 -08:00
|
|
|
List<PhoneNumber> _phoneNumbers = [];
|
Add TWP Softphone Flutter app and complete mobile backend API
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for
mobile VoIP, implement unhold_call() with call leg detection, wire FCM
push notifications into call queue and webhook missed call handlers,
add data-only FCM message support for Android background wake, and add
Twilio API Key / Push Credential settings fields.
Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth
with auto-refresh, SSE real-time queue updates, FCM push notifications,
Material 3 UI with dashboard, active call screen, dialpad, and call
controls (mute/speaker/hold/transfer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:01:23 -08:00
|
|
|
StreamSubscription? _sseSub;
|
|
|
|
|
StreamSubscription? _connSub;
|
|
|
|
|
|
|
|
|
|
AgentStatus? get status => _status;
|
|
|
|
|
List<QueueInfo> get queues => _queues;
|
|
|
|
|
bool get sseConnected => _sseConnected;
|
2026-03-06 18:05:54 -08:00
|
|
|
List<PhoneNumber> get phoneNumbers => _phoneNumbers;
|
Add TWP Softphone Flutter app and complete mobile backend API
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for
mobile VoIP, implement unhold_call() with call leg detection, wire FCM
push notifications into call queue and webhook missed call handlers,
add data-only FCM message support for Android background wake, and add
Twilio API Key / Push Credential settings fields.
Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth
with auto-refresh, SSE real-time queue updates, FCM push notifications,
Material 3 UI with dashboard, active call screen, dialpad, and call
controls (mute/speaker/hold/transfer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:01:23 -08:00
|
|
|
|
|
|
|
|
AgentProvider(this._api, this._sse) {
|
|
|
|
|
_connSub = _sse.connectionState.listen((connected) {
|
|
|
|
|
_sseConnected = connected;
|
|
|
|
|
notifyListeners();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
_sseSub = _sse.events.listen(_handleSseEvent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> fetchStatus() async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _api.dio.get('/agent/status');
|
|
|
|
|
_status = AgentStatus.fromJson(response.data);
|
|
|
|
|
notifyListeners();
|
2026-03-06 18:05:54 -08:00
|
|
|
} catch (e) { debugPrint('AgentProvider.fetchStatus error: $e'); }
|
Add TWP Softphone Flutter app and complete mobile backend API
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for
mobile VoIP, implement unhold_call() with call leg detection, wire FCM
push notifications into call queue and webhook missed call handlers,
add data-only FCM message support for Android background wake, and add
Twilio API Key / Push Credential settings fields.
Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth
with auto-refresh, SSE real-time queue updates, FCM push notifications,
Material 3 UI with dashboard, active call screen, dialpad, and call
controls (mute/speaker/hold/transfer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:01:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> updateStatus(AgentStatusValue newStatus) async {
|
|
|
|
|
final statusStr = newStatus.name;
|
|
|
|
|
try {
|
|
|
|
|
await _api.dio.post('/agent/status', data: {
|
|
|
|
|
'status': statusStr,
|
|
|
|
|
'is_logged_in': true,
|
|
|
|
|
});
|
|
|
|
|
_status = AgentStatus(
|
|
|
|
|
status: newStatus,
|
|
|
|
|
isLoggedIn: true,
|
|
|
|
|
currentCallSid: _status?.currentCallSid,
|
|
|
|
|
);
|
|
|
|
|
notifyListeners();
|
2026-03-06 18:05:54 -08:00
|
|
|
} catch (e) { debugPrint('AgentProvider.updateStatus error: $e'); }
|
Add TWP Softphone Flutter app and complete mobile backend API
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for
mobile VoIP, implement unhold_call() with call leg detection, wire FCM
push notifications into call queue and webhook missed call handlers,
add data-only FCM message support for Android background wake, and add
Twilio API Key / Push Credential settings fields.
Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth
with auto-refresh, SSE real-time queue updates, FCM push notifications,
Material 3 UI with dashboard, active call screen, dialpad, and call
controls (mute/speaker/hold/transfer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:01:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> fetchQueues() async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _api.dio.get('/queues/state');
|
|
|
|
|
final data = response.data;
|
|
|
|
|
_queues = (data['queues'] as List)
|
|
|
|
|
.map((q) => QueueInfo.fromJson(q as Map<String, dynamic>))
|
|
|
|
|
.toList();
|
|
|
|
|
notifyListeners();
|
2026-03-06 18:05:54 -08:00
|
|
|
} catch (e) { debugPrint('AgentProvider.fetchQueues error: $e'); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> fetchPhoneNumbers() async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _api.dio.get('/phone-numbers');
|
|
|
|
|
final data = response.data;
|
|
|
|
|
_phoneNumbers = (data['phone_numbers'] as List)
|
|
|
|
|
.map((p) => PhoneNumber.fromJson(p as Map<String, dynamic>))
|
|
|
|
|
.toList();
|
|
|
|
|
notifyListeners();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
debugPrint('AgentProvider.fetchPhoneNumbers error: $e');
|
|
|
|
|
}
|
Add TWP Softphone Flutter app and complete mobile backend API
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for
mobile VoIP, implement unhold_call() with call leg detection, wire FCM
push notifications into call queue and webhook missed call handlers,
add data-only FCM message support for Android background wake, and add
Twilio API Key / Push Credential settings fields.
Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth
with auto-refresh, SSE real-time queue updates, FCM push notifications,
Material 3 UI with dashboard, active call screen, dialpad, and call
controls (mute/speaker/hold/transfer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:01:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> refresh() async {
|
2026-03-06 18:05:54 -08:00
|
|
|
await Future.wait([fetchStatus(), fetchQueues(), fetchPhoneNumbers()]);
|
Add TWP Softphone Flutter app and complete mobile backend API
Backend: Add /voice/token endpoint with AccessToken + VoiceGrant for
mobile VoIP, implement unhold_call() with call leg detection, wire FCM
push notifications into call queue and webhook missed call handlers,
add data-only FCM message support for Android background wake, and add
Twilio API Key / Push Credential settings fields.
Flutter app: Full softphone with Twilio Voice SDK integration, JWT auth
with auto-refresh, SSE real-time queue updates, FCM push notifications,
Material 3 UI with dashboard, active call screen, dialpad, and call
controls (mute/speaker/hold/transfer).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 13:01:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void _handleSseEvent(SseEvent event) {
|
|
|
|
|
switch (event.event) {
|
|
|
|
|
case 'call_enqueued':
|
|
|
|
|
case 'call_dequeued':
|
|
|
|
|
fetchQueues();
|
|
|
|
|
break;
|
|
|
|
|
case 'agent_status_changed':
|
|
|
|
|
fetchStatus();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
void dispose() {
|
|
|
|
|
_sseSub?.cancel();
|
|
|
|
|
_connSub?.cancel();
|
|
|
|
|
super.dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|