Merge branch 'main' into release
This commit is contained in:
@@ -26,12 +26,14 @@ import '../../repositories/auth_repository.dart';
|
||||
import 'auth_event.dart';
|
||||
import 'auth_state.dart';
|
||||
import '../../services/notification_service.dart';
|
||||
import '../../services/analytics_service.dart';
|
||||
|
||||
/// BLoC for managing authentication state and operations.
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
/// Repository for authentication operations.
|
||||
final AuthRepository _authRepository;
|
||||
final NotificationService _notificationService;
|
||||
final AnalyticsService _analyticsService;
|
||||
|
||||
/// Creates an [AuthBloc] with the provided [authRepository].
|
||||
///
|
||||
@@ -40,8 +42,10 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
AuthBloc({
|
||||
required AuthRepository authRepository,
|
||||
NotificationService? notificationService,
|
||||
AnalyticsService? analyticsService,
|
||||
}) : _authRepository = authRepository,
|
||||
_notificationService = notificationService ?? NotificationService(),
|
||||
_analyticsService = analyticsService ?? AnalyticsService(),
|
||||
super(AuthInitial()) {
|
||||
on<AuthCheckRequested>(_onAuthCheckRequested);
|
||||
on<AuthSignInRequested>(_onSignInRequested);
|
||||
@@ -76,6 +80,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
if (user != null) {
|
||||
// Save FCM Token on auto-login
|
||||
await _notificationService.saveTokenToFirestore(user.id!);
|
||||
await _analyticsService.setUserId(user.id);
|
||||
emit(AuthAuthenticated(user: user));
|
||||
} else {
|
||||
emit(AuthUnauthenticated());
|
||||
@@ -107,6 +112,11 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
if (user != null) {
|
||||
// Save FCM Token
|
||||
await NotificationService().saveTokenToFirestore(user.id!);
|
||||
await _analyticsService.setUserId(user.id);
|
||||
await _analyticsService.logEvent(
|
||||
name: 'login',
|
||||
parameters: {'method': 'email'},
|
||||
);
|
||||
emit(AuthAuthenticated(user: user));
|
||||
} else {
|
||||
emit(const AuthError(message: 'Invalid email or password'));
|
||||
@@ -138,6 +148,11 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
if (user != null) {
|
||||
// Save FCM Token
|
||||
await NotificationService().saveTokenToFirestore(user.id!);
|
||||
await _analyticsService.setUserId(user.id);
|
||||
await _analyticsService.logEvent(
|
||||
name: 'sign_up',
|
||||
parameters: {'method': 'email'},
|
||||
);
|
||||
emit(AuthAuthenticated(user: user));
|
||||
} else {
|
||||
emit(const AuthError(message: 'Failed to create account'));
|
||||
@@ -163,6 +178,11 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
if (user != null) {
|
||||
// Save FCM Token
|
||||
await NotificationService().saveTokenToFirestore(user.id!);
|
||||
await _analyticsService.setUserId(user.id);
|
||||
await _analyticsService.logEvent(
|
||||
name: 'login',
|
||||
parameters: {'method': 'google'},
|
||||
);
|
||||
emit(AuthAuthenticated(user: user));
|
||||
} else {
|
||||
emit(
|
||||
@@ -191,6 +211,11 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
);
|
||||
|
||||
if (user != null) {
|
||||
await _analyticsService.setUserId(user.id);
|
||||
await _analyticsService.logEvent(
|
||||
name: 'sign_up',
|
||||
parameters: {'method': 'google'},
|
||||
);
|
||||
emit(AuthAuthenticated(user: user));
|
||||
} else {
|
||||
emit(const AuthError(message: 'Failed to create account with Google'));
|
||||
@@ -214,6 +239,11 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
);
|
||||
|
||||
if (user != null) {
|
||||
await _analyticsService.setUserId(user.id);
|
||||
await _analyticsService.logEvent(
|
||||
name: 'sign_up',
|
||||
parameters: {'method': 'apple'},
|
||||
);
|
||||
emit(AuthAuthenticated(user: user));
|
||||
} else {
|
||||
emit(const AuthError(message: 'Failed to create account with Apple'));
|
||||
@@ -239,6 +269,11 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
if (user != null) {
|
||||
// Save FCM Token
|
||||
await NotificationService().saveTokenToFirestore(user.id!);
|
||||
await _analyticsService.setUserId(user.id);
|
||||
await _analyticsService.logEvent(
|
||||
name: 'login',
|
||||
parameters: {'method': 'apple'},
|
||||
);
|
||||
emit(AuthAuthenticated(user: user));
|
||||
} else {
|
||||
emit(
|
||||
@@ -261,6 +296,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
await _authRepository.signOut();
|
||||
await _analyticsService.setUserId(null); // Clear user ID
|
||||
emit(AuthUnauthenticated());
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import 'package:travel_mate/services/expense_service.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:travel_mate/services/notification_service.dart';
|
||||
import 'package:travel_mate/services/map_navigation_service.dart';
|
||||
import 'package:travel_mate/services/analytics_service.dart';
|
||||
import 'blocs/auth/auth_bloc.dart';
|
||||
import 'blocs/auth/auth_event.dart';
|
||||
import 'blocs/theme/theme_bloc.dart';
|
||||
@@ -146,6 +147,10 @@ class MyApp extends StatelessWidget {
|
||||
RepositoryProvider<MapNavigationService>(
|
||||
create: (context) => MapNavigationService(),
|
||||
),
|
||||
// Analysis service
|
||||
RepositoryProvider<AnalyticsService>(
|
||||
create: (context) => AnalyticsService(),
|
||||
),
|
||||
],
|
||||
child: MultiBlocProvider(
|
||||
providers: [
|
||||
@@ -206,6 +211,9 @@ class MyApp extends StatelessWidget {
|
||||
title: 'Travel Mate',
|
||||
navigatorKey: ErrorService.navigatorKey,
|
||||
themeMode: themeState.themeMode,
|
||||
navigatorObservers: [
|
||||
context.read<AnalyticsService>().getAnalyticsObserver(),
|
||||
],
|
||||
// Light theme configuration
|
||||
theme: ThemeData(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
|
||||
54
lib/services/analytics_service.dart
Normal file
54
lib/services/analytics_service.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import 'package:firebase_analytics/firebase_analytics.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
/// Service wrapper for Google Analytics
|
||||
class AnalyticsService {
|
||||
final FirebaseAnalytics _analytics = FirebaseAnalytics.instance;
|
||||
|
||||
FirebaseAnalyticsObserver getAnalyticsObserver() =>
|
||||
FirebaseAnalyticsObserver(analytics: _analytics);
|
||||
|
||||
Future<void> logEvent({
|
||||
required String name,
|
||||
Map<String, Object>? parameters,
|
||||
}) async {
|
||||
try {
|
||||
await _analytics.logEvent(name: name, parameters: parameters);
|
||||
} catch (e) {
|
||||
debugPrint('Error logging analytics event: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setUserProperty({
|
||||
required String name,
|
||||
required String? value,
|
||||
}) async {
|
||||
try {
|
||||
await _analytics.setUserProperty(name: name, value: value);
|
||||
} catch (e) {
|
||||
debugPrint('Error setting user property: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setUserId(String? id) async {
|
||||
try {
|
||||
await _analytics.setUserId(id: id);
|
||||
} catch (e) {
|
||||
debugPrint('Error setting user ID: $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> logScreenView({
|
||||
required String screenName,
|
||||
String? screenClass,
|
||||
}) async {
|
||||
try {
|
||||
await _analytics.logScreenView(
|
||||
screenName: screenName,
|
||||
screenClass: screenClass,
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('Error logging screen view: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user