All checks were successful
Create Release / build (push) Successful in 3s
- Voice token: use AccessToken + VoiceGrant instead of browser-only ClientToken - Agent status: delegate to TWP_Agent_Manager matching browser phone behavior - Queue loading: add missing require_once for TWP_User_Queue_Manager - Add /phone-numbers endpoint for caller ID selection - Webhook: support CallerId param from mobile extraOptions - Flutter: caller ID dropdown in dialer, error logging in all catch blocks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
114 lines
3.0 KiB
Dart
114 lines
3.0 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 final AuthService _authService;
|
|
late final VoiceService _voiceService;
|
|
late final PushNotificationService _pushService;
|
|
late final 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 restored = await _authService.tryRestoreSession();
|
|
if (restored) {
|
|
_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();
|
|
} 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() {
|
|
_state = AuthState.unauthenticated;
|
|
_user = null;
|
|
_error = 'Session expired. Please log in again.';
|
|
_sseService.disconnect();
|
|
notifyListeners();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_authService.dispose();
|
|
_voiceService.dispose();
|
|
_sseService.dispose();
|
|
super.dispose();
|
|
}
|
|
}
|