Phase 2 refinements: Firebase config, dev environment fixes, phase 3 requirement draft
- Integrated Firebase SDK in both Flutter apps (google-services, firebase_options) - Fixed auth flow, API client, and pairing/status blocs for dev environment - Added full Flutter project scaffolds (android, ios, web, etc.) - Added phase 3 chat engine requirement document - Added bugreport zip pattern to gitignore Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -32,4 +32,8 @@ class ApiClient {
|
||||
final response = await _dio.get(path, queryParameters: queryParameters);
|
||||
return response.data as Map<String, dynamic>;
|
||||
}
|
||||
|
||||
Future<Response> getStream(String path) async {
|
||||
return _dio.get(path, options: Options(responseType: ResponseType.stream));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,11 +91,10 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final customerId = prefs.getString('anonymous_customer_id');
|
||||
final displayName = prefs.getString('anonymous_display_name');
|
||||
final currentUser = _auth.currentUser;
|
||||
|
||||
if (_auth.currentUser != null) {
|
||||
await _verifyAndEmit(emit);
|
||||
} else if (customerId != null && displayName != null) {
|
||||
// Check anonymity config
|
||||
if (currentUser != null && currentUser.isAnonymous && customerId != null && displayName != null) {
|
||||
// Anonymous Firebase user — restore anonymous state
|
||||
try {
|
||||
final config = await apiClient.get('/api/shared/config/anonymity');
|
||||
final anonymityEnabled = config['data']['anonymity_enabled'] as bool;
|
||||
@@ -107,6 +106,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
} catch (_) {
|
||||
emit(AuthAnonymous(customerId: customerId, displayName: displayName));
|
||||
}
|
||||
} else if (currentUser != null && !currentUser.isAnonymous) {
|
||||
// Fully registered Firebase user
|
||||
await _verifyAndEmit(emit);
|
||||
} else {
|
||||
emit(AuthInitial());
|
||||
}
|
||||
@@ -115,6 +117,10 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
Future<void> _onAnonymousLogin(AnonymousLoginRequested event, Emitter<AuthState> emit) async {
|
||||
emit(AuthLoading());
|
||||
try {
|
||||
// Sign in anonymously with Firebase to get a real JWT
|
||||
await _auth.signInAnonymously();
|
||||
|
||||
// Create/get customer record on backend linked to this Firebase UID
|
||||
final response = await apiClient.post(
|
||||
'/api/shared/customer/anonymous',
|
||||
data: {'display_name': event.displayName},
|
||||
|
||||
@@ -77,6 +77,10 @@ class PairingBloc extends Bloc<PairingEvent, PairingState> {
|
||||
}
|
||||
|
||||
Future<void> _onRequestPairing(RequestPairing event, Emitter<PairingState> emit) async {
|
||||
// Reset to initial so BlocListener can detect new errors
|
||||
if (state is! PairingInitial) {
|
||||
emit(PairingInitial());
|
||||
}
|
||||
try {
|
||||
final response = await apiClient.post('/api/client/chat/request');
|
||||
final data = response['data'] as Map<String, dynamic>;
|
||||
@@ -104,12 +108,7 @@ class PairingBloc extends Bloc<PairingEvent, PairingState> {
|
||||
}
|
||||
|
||||
void _listenToSSE(String sessionId) {
|
||||
final dio = Dio(BaseOptions(baseUrl: ApiClient.baseUrl));
|
||||
// SSE endpoint — use responseType stream
|
||||
dio.get(
|
||||
'/api/client/chat/request/$sessionId/status',
|
||||
options: Options(responseType: ResponseType.stream),
|
||||
).then((response) {
|
||||
apiClient.getStream('/api/client/chat/request/$sessionId/status').then((response) {
|
||||
final stream = response.data.stream as Stream<List<int>>;
|
||||
_sseSubscription = stream
|
||||
.transform(utf8.decoder)
|
||||
|
||||
Reference in New Issue
Block a user