All checks were successful
Create Release / build (push) Successful in 6s
Server-side: - Add push credential auto-creation for FCM incoming call notifications - Add queue alert FCM notifications (data-only for background delivery) - Add queue alert cancellation on call accept/disconnect - Fix caller ID to show caller's number instead of Twilio number - Fix FCM token storage when refresh_token is null - Add pre_call_status tracking to revert agent status 30s after call ends - Add SSE fallback polling for mobile app connectivity Mobile app: - Add Android telecom permissions and phone account registration - Add VoiceFirebaseMessagingService for incoming call push handling - Add insistent queue alert notifications with custom sound - Fix caller number display on active call screen - Add caller ID selection dropdown on dashboard - Add phone numbers endpoint and provider support - Add unit tests for CallInfo, QueueState, and CallProvider - Remove local.properties from tracking, add .gitignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
123 lines
3.3 KiB
Dart
123 lines
3.3 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import '../models/user.dart';
|
|
import '../services/api_client.dart';
|
|
import '../services/auth_service.dart';
|
|
import '../services/voice_service.dart';
|
|
import '../services/push_notification_service.dart';
|
|
import '../services/sse_service.dart';
|
|
|
|
enum AuthState { unauthenticated, authenticating, authenticated }
|
|
|
|
class AuthProvider extends ChangeNotifier {
|
|
final ApiClient _apiClient;
|
|
late AuthService _authService;
|
|
late VoiceService _voiceService;
|
|
late PushNotificationService _pushService;
|
|
late SseService _sseService;
|
|
|
|
AuthState _state = AuthState.unauthenticated;
|
|
User? _user;
|
|
String? _error;
|
|
|
|
AuthState get state => _state;
|
|
User? get user => _user;
|
|
String? get error => _error;
|
|
VoiceService get voiceService => _voiceService;
|
|
SseService get sseService => _sseService;
|
|
ApiClient get apiClient => _apiClient;
|
|
|
|
AuthProvider(this._apiClient) {
|
|
_authService = AuthService(_apiClient);
|
|
_voiceService = VoiceService(_apiClient);
|
|
_pushService = PushNotificationService(_apiClient);
|
|
_sseService = SseService(_apiClient);
|
|
|
|
_apiClient.onForceLogout = _handleForceLogout;
|
|
}
|
|
|
|
Future<void> tryRestoreSession() async {
|
|
final user = await _authService.tryRestoreSession();
|
|
if (user != null) {
|
|
_user = user;
|
|
_state = AuthState.authenticated;
|
|
await _initializeServices();
|
|
notifyListeners();
|
|
}
|
|
}
|
|
|
|
Future<void> login(String serverUrl, String username, String password) async {
|
|
_state = AuthState.authenticating;
|
|
_error = null;
|
|
notifyListeners();
|
|
|
|
try {
|
|
_user = await _authService.login(serverUrl, username, password);
|
|
_state = AuthState.authenticated;
|
|
await _initializeServices();
|
|
} catch (e) {
|
|
_state = AuthState.unauthenticated;
|
|
_error = e.toString().replaceFirst('Exception: ', '');
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> _initializeServices() async {
|
|
try {
|
|
await _pushService.initialize();
|
|
} catch (e) {
|
|
debugPrint('AuthProvider: push service init error: $e');
|
|
}
|
|
try {
|
|
await _voiceService.initialize(deviceToken: _pushService.fcmToken);
|
|
} catch (e) {
|
|
debugPrint('AuthProvider: voice service init error: $e');
|
|
}
|
|
try {
|
|
await _sseService.connect();
|
|
} catch (e) {
|
|
debugPrint('AuthProvider: SSE connect error: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> logout() async {
|
|
_voiceService.dispose();
|
|
_sseService.disconnect();
|
|
await _authService.logout();
|
|
|
|
_state = AuthState.unauthenticated;
|
|
_user = null;
|
|
_error = null;
|
|
|
|
// Re-create services for potential re-login
|
|
_voiceService = VoiceService(_apiClient);
|
|
_pushService = PushNotificationService(_apiClient);
|
|
_sseService = SseService(_apiClient);
|
|
|
|
notifyListeners();
|
|
}
|
|
|
|
void _handleForceLogout() {
|
|
_voiceService.dispose();
|
|
_sseService.disconnect();
|
|
|
|
_state = AuthState.unauthenticated;
|
|
_user = null;
|
|
_error = 'Session expired. Please log in again.';
|
|
|
|
// Re-create services for potential re-login
|
|
_voiceService = VoiceService(_apiClient);
|
|
_pushService = PushNotificationService(_apiClient);
|
|
_sseService = SseService(_apiClient);
|
|
|
|
notifyListeners();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_authService.dispose();
|
|
_voiceService.dispose();
|
|
_sseService.dispose();
|
|
super.dispose();
|
|
}
|
|
}
|