refactor: remove analytics module, update tool postprocessor tests
This commit is contained in:
@@ -1,111 +0,0 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class AnalyticsContext extends Equatable {
|
||||
final String? networkType;
|
||||
final String? osVersion;
|
||||
final String? deviceModel;
|
||||
final String? locale;
|
||||
final String? timezone;
|
||||
|
||||
const AnalyticsContext({
|
||||
this.networkType,
|
||||
this.osVersion,
|
||||
this.deviceModel,
|
||||
this.locale,
|
||||
this.timezone,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'network_type': networkType,
|
||||
'os_version': osVersion,
|
||||
'device_model': deviceModel,
|
||||
'locale': locale,
|
||||
'timezone': timezone,
|
||||
};
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
networkType,
|
||||
osVersion,
|
||||
deviceModel,
|
||||
locale,
|
||||
timezone,
|
||||
];
|
||||
}
|
||||
|
||||
class BaseAnalyticsEvent extends Equatable {
|
||||
final String eventId;
|
||||
final String eventType;
|
||||
final DateTime timestamp;
|
||||
final String userId;
|
||||
final String deviceId;
|
||||
final String sessionId;
|
||||
final String platform;
|
||||
final String appVersion;
|
||||
final String? appBuild;
|
||||
final String env;
|
||||
final String? pageName;
|
||||
final String? traceId;
|
||||
final String? requestId;
|
||||
final Map<String, dynamic> attributes;
|
||||
final Map<String, num> metrics;
|
||||
final AnalyticsContext? context;
|
||||
|
||||
const BaseAnalyticsEvent({
|
||||
required this.eventId,
|
||||
required this.eventType,
|
||||
required this.timestamp,
|
||||
required this.userId,
|
||||
required this.deviceId,
|
||||
required this.sessionId,
|
||||
required this.platform,
|
||||
required this.appVersion,
|
||||
this.appBuild,
|
||||
required this.env,
|
||||
this.pageName,
|
||||
this.traceId,
|
||||
this.requestId,
|
||||
this.attributes = const {},
|
||||
this.metrics = const {},
|
||||
this.context,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'event_id': eventId,
|
||||
'event_type': eventType,
|
||||
'timestamp': timestamp.toUtc().toIso8601String(),
|
||||
'user_id': userId,
|
||||
'device_id': deviceId,
|
||||
'session_id': sessionId,
|
||||
'platform': platform,
|
||||
'app_version': appVersion,
|
||||
'app_build': appBuild,
|
||||
'env': env,
|
||||
'page_name': pageName,
|
||||
'trace_id': traceId,
|
||||
'request_id': requestId,
|
||||
'attributes': attributes,
|
||||
'metrics': metrics,
|
||||
'context': context?.toJson(),
|
||||
};
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
eventId,
|
||||
eventType,
|
||||
timestamp,
|
||||
userId,
|
||||
deviceId,
|
||||
sessionId,
|
||||
platform,
|
||||
appVersion,
|
||||
appBuild,
|
||||
env,
|
||||
pageName,
|
||||
traceId,
|
||||
requestId,
|
||||
attributes,
|
||||
metrics,
|
||||
context,
|
||||
];
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import 'base_event.dart';
|
||||
|
||||
class UiClickEvent extends BaseAnalyticsEvent {
|
||||
UiClickEvent({
|
||||
required super.eventId,
|
||||
required super.timestamp,
|
||||
required super.userId,
|
||||
required super.deviceId,
|
||||
required super.sessionId,
|
||||
required super.platform,
|
||||
required super.appVersion,
|
||||
super.appBuild,
|
||||
required super.env,
|
||||
required super.pageName,
|
||||
super.traceId,
|
||||
super.requestId,
|
||||
required String elementId,
|
||||
String? elementType,
|
||||
super.context,
|
||||
}) : super(
|
||||
eventType: 'ui.click',
|
||||
attributes: {
|
||||
'element_id': elementId,
|
||||
if (elementType != null) 'element_type': elementType,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import 'base_event.dart';
|
||||
|
||||
class AgentChatCompletedEvent extends BaseAnalyticsEvent {
|
||||
AgentChatCompletedEvent({
|
||||
required super.eventId,
|
||||
required super.timestamp,
|
||||
required super.userId,
|
||||
required super.deviceId,
|
||||
required super.sessionId,
|
||||
required super.platform,
|
||||
required super.appVersion,
|
||||
super.appBuild,
|
||||
required super.env,
|
||||
super.pageName,
|
||||
super.traceId,
|
||||
super.requestId,
|
||||
required String conversationId,
|
||||
String? scenario,
|
||||
int? messageCount,
|
||||
int? responseTimeMs,
|
||||
AnalyticsContext? context,
|
||||
}) : super(
|
||||
eventType: 'agent.chat_completed',
|
||||
attributes: {
|
||||
'conversation_id': conversationId,
|
||||
if (scenario != null) 'scenario': scenario,
|
||||
},
|
||||
metrics: {
|
||||
if (messageCount != null) 'message_count': messageCount,
|
||||
if (responseTimeMs != null) 'response_time_ms': responseTimeMs,
|
||||
},
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export 'base_event.dart';
|
||||
export 'login_event.dart';
|
||||
export 'logout_event.dart';
|
||||
export 'conversation_event.dart';
|
||||
export 'page_view_event.dart';
|
||||
export 'click_event.dart';
|
||||
@@ -1,24 +0,0 @@
|
||||
import 'base_event.dart';
|
||||
|
||||
class SessionLoginEvent extends BaseAnalyticsEvent {
|
||||
SessionLoginEvent({
|
||||
required super.eventId,
|
||||
required super.timestamp,
|
||||
required super.userId,
|
||||
required super.deviceId,
|
||||
required super.sessionId,
|
||||
required super.platform,
|
||||
required super.appVersion,
|
||||
super.appBuild,
|
||||
required super.env,
|
||||
super.pageName,
|
||||
super.traceId,
|
||||
super.requestId,
|
||||
required String method,
|
||||
AnalyticsContext? context,
|
||||
}) : super(
|
||||
eventType: 'session.login',
|
||||
attributes: {'method': method},
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import 'base_event.dart';
|
||||
|
||||
class SessionLogoutEvent extends BaseAnalyticsEvent {
|
||||
SessionLogoutEvent({
|
||||
required super.eventId,
|
||||
required super.timestamp,
|
||||
required super.userId,
|
||||
required super.deviceId,
|
||||
required super.sessionId,
|
||||
required super.platform,
|
||||
required super.appVersion,
|
||||
super.appBuild,
|
||||
required super.env,
|
||||
super.pageName,
|
||||
super.traceId,
|
||||
super.requestId,
|
||||
String? reason,
|
||||
int? sessionDurationS,
|
||||
AnalyticsContext? context,
|
||||
}) : super(
|
||||
eventType: 'session.logout',
|
||||
attributes: reason != null ? {'reason': reason} : const {},
|
||||
metrics: sessionDurationS != null
|
||||
? {'session_duration_s': sessionDurationS}
|
||||
: const {},
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'base_event.dart';
|
||||
|
||||
class PageViewEvent extends BaseAnalyticsEvent {
|
||||
PageViewEvent({
|
||||
required super.eventId,
|
||||
required super.timestamp,
|
||||
required super.userId,
|
||||
required super.deviceId,
|
||||
required super.sessionId,
|
||||
required super.platform,
|
||||
required super.appVersion,
|
||||
super.appBuild,
|
||||
required super.env,
|
||||
required super.pageName,
|
||||
super.traceId,
|
||||
super.requestId,
|
||||
String? pageFrom,
|
||||
int? stayDurationMs,
|
||||
int? clickCount,
|
||||
super.context,
|
||||
}) : super(
|
||||
eventType: 'page.view',
|
||||
attributes: pageFrom != null ? {'page_from': pageFrom} : const {},
|
||||
metrics: {
|
||||
if (stayDurationMs != null) 'stay_duration_ms': stayDurationMs,
|
||||
if (clickCount != null) 'click_count': clickCount,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import 'dart:async';
|
||||
|
||||
import '../events/events.dart';
|
||||
|
||||
class EventQueue {
|
||||
final List<BaseAnalyticsEvent> _queue = [];
|
||||
final int maxSize;
|
||||
final Duration flushInterval;
|
||||
final void Function(List<BaseAnalyticsEvent>) onFlush;
|
||||
|
||||
Timer? _timer;
|
||||
|
||||
EventQueue({
|
||||
this.maxSize = 50,
|
||||
this.flushInterval = const Duration(seconds: 30),
|
||||
required this.onFlush,
|
||||
});
|
||||
|
||||
void start() {
|
||||
_timer?.cancel();
|
||||
_timer = Timer.periodic(flushInterval, (_) => _tryFlush());
|
||||
}
|
||||
|
||||
void stop() {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
}
|
||||
|
||||
void add(BaseAnalyticsEvent event) {
|
||||
_queue.add(event);
|
||||
if (_queue.length >= maxSize) {
|
||||
_tryFlush();
|
||||
}
|
||||
}
|
||||
|
||||
void _tryFlush() {
|
||||
if (_queue.isEmpty) return;
|
||||
final events = List<BaseAnalyticsEvent>.from(_queue);
|
||||
_queue.clear();
|
||||
onFlush(events);
|
||||
}
|
||||
|
||||
List<BaseAnalyticsEvent> get pendingEvents => List.unmodifiable(_queue);
|
||||
|
||||
int get pendingCount => _queue.length;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import 'events/events.dart';
|
||||
|
||||
class AnalyticsSender {
|
||||
final Dio _dio;
|
||||
final String endpoint;
|
||||
|
||||
AnalyticsSender({required this.endpoint, Dio? dio}) : _dio = dio ?? Dio();
|
||||
|
||||
Future<void> send(List<BaseAnalyticsEvent> events) async {
|
||||
if (events.isEmpty) return;
|
||||
|
||||
final body = {'events': events.map((e) => e.toJson()).toList()};
|
||||
|
||||
try {
|
||||
await _dio.post(
|
||||
endpoint,
|
||||
data: jsonEncode(body),
|
||||
options: Options(
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
sendTimeout: const Duration(seconds: 10),
|
||||
receiveTimeout: const Duration(seconds: 10),
|
||||
),
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
throw AnalyticsSendException(
|
||||
'Failed to send analytics events: ${e.message}',
|
||||
events: events,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AnalyticsSendException implements Exception {
|
||||
final String message;
|
||||
final List<BaseAnalyticsEvent> events;
|
||||
|
||||
AnalyticsSendException(this.message, {required this.events});
|
||||
|
||||
@override
|
||||
String toString() => 'AnalyticsSendException: $message';
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'events/events.dart';
|
||||
import 'queue/event_queue.dart';
|
||||
import 'sender.dart';
|
||||
|
||||
class AnalyticsTracker {
|
||||
static AnalyticsTracker? _instance;
|
||||
|
||||
late final AnalyticsSender _sender;
|
||||
late final EventQueue _queue;
|
||||
late final String _deviceId;
|
||||
late final String _sessionId;
|
||||
late final String _platform;
|
||||
late final String _appVersion;
|
||||
late final String? _appBuild;
|
||||
late final String _env;
|
||||
|
||||
String? _userId;
|
||||
|
||||
AnalyticsTracker._();
|
||||
|
||||
static AnalyticsTracker get instance {
|
||||
if (_instance == null) {
|
||||
throw StateError('AnalyticsTracker not initialized. Call init() first.');
|
||||
}
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
static Future<void> init({
|
||||
required String endpoint,
|
||||
required String deviceId,
|
||||
}) async {
|
||||
if (_instance != null) return;
|
||||
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
|
||||
final sessionId = await _getOrCreateSessionId();
|
||||
final platform = Platform.isAndroid ? 'android' : 'ios';
|
||||
final env = kDebugMode ? 'dev' : 'prod';
|
||||
|
||||
final tracker = AnalyticsTracker._();
|
||||
tracker._sender = AnalyticsSender(endpoint: endpoint);
|
||||
tracker._queue = EventQueue(
|
||||
maxSize: 50,
|
||||
flushInterval: const Duration(seconds: 30),
|
||||
onFlush: tracker._handleFlush,
|
||||
);
|
||||
tracker._deviceId = deviceId;
|
||||
tracker._sessionId = sessionId;
|
||||
tracker._platform = platform;
|
||||
tracker._appVersion = packageInfo.version;
|
||||
tracker._appBuild = packageInfo.buildNumber.isNotEmpty
|
||||
? packageInfo.buildNumber
|
||||
: null;
|
||||
tracker._env = env;
|
||||
|
||||
tracker._queue.start();
|
||||
_instance = tracker;
|
||||
}
|
||||
|
||||
static Future<String> _getOrCreateSessionId() async {
|
||||
const uuid = Uuid();
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
var sessionId = prefs.getString('_analytics_session_id');
|
||||
if (sessionId == null) {
|
||||
sessionId = 'sess_${uuid.v4()}';
|
||||
await prefs.setString('_analytics_session_id', sessionId);
|
||||
}
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
void setUserId(String? userId) {
|
||||
_userId = userId;
|
||||
}
|
||||
|
||||
String get userId => _userId ?? 'anonymous';
|
||||
|
||||
String get sessionId => _sessionId;
|
||||
|
||||
void track(BaseAnalyticsEvent event) {
|
||||
_queue.add(event);
|
||||
}
|
||||
|
||||
void trackLogin({
|
||||
required String method,
|
||||
String? traceId,
|
||||
String? requestId,
|
||||
AnalyticsContext? context,
|
||||
}) {
|
||||
track(
|
||||
SessionLoginEvent(
|
||||
eventId: _generateEventId(),
|
||||
timestamp: DateTime.now(),
|
||||
userId: userId,
|
||||
deviceId: _deviceId,
|
||||
sessionId: _sessionId,
|
||||
platform: _platform,
|
||||
appVersion: _appVersion,
|
||||
appBuild: _appBuild,
|
||||
env: _env,
|
||||
pageName: 'login',
|
||||
traceId: traceId,
|
||||
requestId: requestId,
|
||||
method: method,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void trackLogout({
|
||||
String? reason,
|
||||
int? sessionDurationS,
|
||||
String? pageName,
|
||||
String? traceId,
|
||||
AnalyticsContext? context,
|
||||
}) {
|
||||
track(
|
||||
SessionLogoutEvent(
|
||||
eventId: _generateEventId(),
|
||||
timestamp: DateTime.now(),
|
||||
userId: userId,
|
||||
deviceId: _deviceId,
|
||||
sessionId: _sessionId,
|
||||
platform: _platform,
|
||||
appVersion: _appVersion,
|
||||
appBuild: _appBuild,
|
||||
env: _env,
|
||||
pageName: pageName,
|
||||
traceId: traceId,
|
||||
reason: reason,
|
||||
sessionDurationS: sessionDurationS,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void trackAgentChatCompleted({
|
||||
required String conversationId,
|
||||
String? scenario,
|
||||
int? messageCount,
|
||||
int? responseTimeMs,
|
||||
String? traceId,
|
||||
String? requestId,
|
||||
AnalyticsContext? context,
|
||||
}) {
|
||||
track(
|
||||
AgentChatCompletedEvent(
|
||||
eventId: _generateEventId(),
|
||||
timestamp: DateTime.now(),
|
||||
userId: userId,
|
||||
deviceId: _deviceId,
|
||||
sessionId: _sessionId,
|
||||
platform: _platform,
|
||||
appVersion: _appVersion,
|
||||
appBuild: _appBuild,
|
||||
env: _env,
|
||||
pageName: 'chat',
|
||||
traceId: traceId,
|
||||
requestId: requestId,
|
||||
conversationId: conversationId,
|
||||
scenario: scenario,
|
||||
messageCount: messageCount,
|
||||
responseTimeMs: responseTimeMs,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void trackPageView({
|
||||
required String pageName,
|
||||
String? pageFrom,
|
||||
int? stayDurationMs,
|
||||
int? clickCount,
|
||||
String? traceId,
|
||||
AnalyticsContext? context,
|
||||
}) {
|
||||
track(
|
||||
PageViewEvent(
|
||||
eventId: _generateEventId(),
|
||||
timestamp: DateTime.now(),
|
||||
userId: userId,
|
||||
deviceId: _deviceId,
|
||||
sessionId: _sessionId,
|
||||
platform: _platform,
|
||||
appVersion: _appVersion,
|
||||
appBuild: _appBuild,
|
||||
env: _env,
|
||||
pageName: pageName,
|
||||
pageFrom: pageFrom,
|
||||
stayDurationMs: stayDurationMs,
|
||||
clickCount: clickCount,
|
||||
traceId: traceId,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void trackClick({
|
||||
required String pageName,
|
||||
required String elementId,
|
||||
String? elementType,
|
||||
String? traceId,
|
||||
AnalyticsContext? context,
|
||||
}) {
|
||||
track(
|
||||
UiClickEvent(
|
||||
eventId: _generateEventId(),
|
||||
timestamp: DateTime.now(),
|
||||
userId: userId,
|
||||
deviceId: _deviceId,
|
||||
sessionId: _sessionId,
|
||||
platform: _platform,
|
||||
appVersion: _appVersion,
|
||||
appBuild: _appBuild,
|
||||
env: _env,
|
||||
pageName: pageName,
|
||||
elementId: elementId,
|
||||
elementType: elementType,
|
||||
traceId: traceId,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _generateEventId() {
|
||||
return const Uuid().v4();
|
||||
}
|
||||
|
||||
Future<void> _handleFlush(List<BaseAnalyticsEvent> events) async {
|
||||
try {
|
||||
await _sender.send(events);
|
||||
} catch (e) {
|
||||
// TODO: 失败时落盘本地,下次启动重试
|
||||
debugPrint('Analytics send failed: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_queue.stop();
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@ class Env {
|
||||
return 'http://localhost:5775';
|
||||
}
|
||||
|
||||
static String get analyticsEndpoint => '$apiUrl/api/v1/analytics/events';
|
||||
|
||||
static String version = '0.1.0';
|
||||
static int build = 1;
|
||||
static String deviceId = '';
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../../core/analytics/tracker.dart';
|
||||
import '../../../../core/logging/logger.dart';
|
||||
import '../../data/repositories/auth_repository.dart';
|
||||
import 'auth_event.dart';
|
||||
@@ -8,7 +7,6 @@ import 'auth_state.dart';
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final AuthRepository _repository;
|
||||
final Logger _logger = getLogger('features.auth.bloc');
|
||||
DateTime? _loginTime;
|
||||
|
||||
AuthBloc(this._repository) : super(AuthInitial()) {
|
||||
on<AuthStarted>(_onStarted);
|
||||
@@ -23,8 +21,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final refreshToken = await _repository.getRefreshToken();
|
||||
if (refreshToken != null) {
|
||||
final response = await _repository.refreshSession(refreshToken);
|
||||
_loginTime = DateTime.now();
|
||||
AnalyticsTracker.instance.setUserId(response.user.id);
|
||||
emit(
|
||||
AuthAuthenticated(
|
||||
user: AuthUser(id: response.user.id, phone: response.user.phone),
|
||||
@@ -60,7 +56,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
|
||||
void _onLoggedIn(AuthLoggedIn event, Emitter<AuthState> emit) {
|
||||
_loginTime = DateTime.now();
|
||||
_logger.info(message: 'User logged in', extra: {'user_id': event.user.id});
|
||||
emit(AuthAuthenticated(user: event.user));
|
||||
}
|
||||
@@ -69,9 +64,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
AuthLoggedOut event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
final sessionDuration = _loginTime != null
|
||||
? DateTime.now().difference(_loginTime!).inSeconds
|
||||
: null;
|
||||
try {
|
||||
await _repository.deleteSession();
|
||||
_logger.info(message: 'User logged out');
|
||||
@@ -82,11 +74,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
} finally {
|
||||
AnalyticsTracker.instance.trackLogout(
|
||||
reason: 'manual',
|
||||
sessionDurationS: sessionDuration,
|
||||
);
|
||||
_loginTime = null;
|
||||
emit(
|
||||
const AuthUnauthenticated(reason: AuthUnauthenticatedReason.signedOut),
|
||||
);
|
||||
@@ -97,9 +84,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
AuthSessionInvalidated event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
final sessionDuration = _loginTime != null
|
||||
? DateTime.now().difference(_loginTime!).inSeconds
|
||||
: null;
|
||||
_logger.warning(message: 'Session invalidated by server');
|
||||
try {
|
||||
await _repository.clearSessionLocalOnly();
|
||||
@@ -110,11 +94,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
} finally {
|
||||
AnalyticsTracker.instance.trackLogout(
|
||||
reason: 'expired',
|
||||
sessionDurationS: sessionDuration,
|
||||
);
|
||||
_loginTime = null;
|
||||
emit(
|
||||
const AuthUnauthenticated(reason: AuthUnauthenticatedReason.expired),
|
||||
);
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../../app/di/injection.dart';
|
||||
import '../../../../app/router/app_routes.dart';
|
||||
import '../../../../core/analytics/tracker.dart';
|
||||
import '../../../../core/l10n/l10n.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import '../../../../shared/widgets/app_button.dart';
|
||||
@@ -70,8 +69,6 @@ class _LoginViewState extends State<LoginView> {
|
||||
|
||||
final response = await cubit.submit();
|
||||
if (response != null && mounted) {
|
||||
AnalyticsTracker.instance.trackLogin(method: 'phone_code');
|
||||
AnalyticsTracker.instance.setUserId(response.user.id);
|
||||
context.read<AuthBloc>().add(AuthLoggedIn(user: response.user));
|
||||
context.go(AppRoutes.homeMain);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import 'package:social_app/core/chat/chat_list_item.dart';
|
||||
import 'package:social_app/core/chat/chat_orchestrator.dart';
|
||||
import 'package:social_app/core/chat/chat_history_repository.dart';
|
||||
import 'package:social_app/core/chat/chat_timeline_reconciler.dart';
|
||||
import 'package:social_app/core/analytics/tracker.dart';
|
||||
import 'package:social_app/core/l10n/l10n.dart';
|
||||
import 'chat_bloc_recovery_utils.dart';
|
||||
|
||||
@@ -318,14 +317,7 @@ class ChatBloc extends Cubit<ChatState> implements ChatOrchestrator {
|
||||
messageCount: 1,
|
||||
responseTimeMs: responseTimeMs,
|
||||
);
|
||||
return;
|
||||
}
|
||||
AnalyticsTracker.instance.trackAgentChatCompleted(
|
||||
conversationId: conversationId,
|
||||
scenario: 'assistant',
|
||||
messageCount: 1,
|
||||
responseTimeMs: responseTimeMs,
|
||||
);
|
||||
}
|
||||
|
||||
void _clearRunMetrics() {
|
||||
|
||||
@@ -12,7 +12,6 @@ import '../../../../app/di/injection.dart';
|
||||
import '../../../../app/router/app_route_observer.dart';
|
||||
import '../../../../app/router/app_routes.dart';
|
||||
import '../../../../core/l10n/l10n.dart';
|
||||
import '../../../../core/analytics/tracker.dart';
|
||||
import '../../../../core/theme/design_tokens.dart';
|
||||
import '../../../../core/inbox/inbox_sync_store.dart';
|
||||
import '../../../chat/presentation/bloc/chat_bloc.dart';
|
||||
@@ -99,8 +98,6 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
int _previousItemCount = 0;
|
||||
bool _previousIsLoadingHistory = false;
|
||||
bool _routeAwareSubscribed = false;
|
||||
late final DateTime _pageEnteredAt;
|
||||
int _pageClickCount = 0;
|
||||
double? _historyViewportPixels;
|
||||
double? _historyViewportMaxExtent;
|
||||
final GlobalKey<HomeInputHostState> _inputHostKey =
|
||||
@@ -124,7 +121,6 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
duration: const Duration(milliseconds: _rippleDurationMs),
|
||||
);
|
||||
_selectedImages.addAll(widget.initialSelectedImages);
|
||||
_pageEnteredAt = DateTime.now();
|
||||
final initialUserId = widget.initialUserId?.trim();
|
||||
if (initialUserId != null && initialUserId.isNotEmpty) {
|
||||
unawaited(_chatBloc.switchUser(initialUserId));
|
||||
@@ -152,14 +148,6 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
final stayDurationMs = DateTime.now()
|
||||
.difference(_pageEnteredAt)
|
||||
.inMilliseconds;
|
||||
AnalyticsTracker.instance.trackPageView(
|
||||
pageName: 'home',
|
||||
stayDurationMs: stayDurationMs,
|
||||
clickCount: _pageClickCount,
|
||||
);
|
||||
_messageController.dispose();
|
||||
_scrollController.removeListener(_handleScrollChanged);
|
||||
_scrollController.dispose();
|
||||
@@ -294,15 +282,15 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
return HomeFloatingHeader(
|
||||
unreadCount: _unreadCount,
|
||||
onTapSettings: () {
|
||||
_trackClick('header_settings');
|
||||
|
||||
context.push(AppRoutes.settingsMain);
|
||||
},
|
||||
onTapCalendar: () {
|
||||
_trackClick('header_calendar');
|
||||
|
||||
context.push('${AppRoutes.calendarDayWeek}?from=home');
|
||||
},
|
||||
onTapMessages: () {
|
||||
_trackClick('header_messages');
|
||||
|
||||
context.push(AppRoutes.messageInviteList);
|
||||
},
|
||||
);
|
||||
@@ -414,7 +402,7 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
child: HomeUnreadBadge(
|
||||
count: _chatUnreadBadgeCount,
|
||||
onTap: () {
|
||||
_trackClick('unread_badge');
|
||||
|
||||
_scheduleAutoScroll(animated: true);
|
||||
if (mounted) {
|
||||
setState(() => _chatUnreadBadgeCount = 0);
|
||||
@@ -467,7 +455,7 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
}
|
||||
|
||||
Future<void> _onLoadMore(BuildContext context) async {
|
||||
_trackClick('history_load_more');
|
||||
|
||||
final chatBloc = context.read<ChatBloc>();
|
||||
await _loadMoreHistoryPreservingViewport(chatBloc);
|
||||
}
|
||||
@@ -681,15 +669,15 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
messageController: _messageController,
|
||||
onTapPlus: _isRecording
|
||||
? () {
|
||||
_trackClick('record_stop');
|
||||
|
||||
_stopRecording(autoSendAfterTranscribe: false);
|
||||
}
|
||||
: () {
|
||||
_trackClick('input_plus');
|
||||
|
||||
_showBottomSheet(context);
|
||||
},
|
||||
onStopGenerating: () {
|
||||
_trackClick('stop_generating');
|
||||
|
||||
_onStopGenerating();
|
||||
},
|
||||
onHoldToSpeakStart: _onHoldToSpeakStart,
|
||||
@@ -701,15 +689,6 @@ class _HomeScreenState extends State<HomeScreen>
|
||||
);
|
||||
}
|
||||
|
||||
void _trackClick(String elementId) {
|
||||
_pageClickCount += 1;
|
||||
AnalyticsTracker.instance.trackClick(
|
||||
pageName: 'home',
|
||||
elementId: elementId,
|
||||
elementType: 'button',
|
||||
);
|
||||
}
|
||||
|
||||
void _removeImage(int index) {
|
||||
setState(() {
|
||||
_selectedImages.removeAt(index);
|
||||
|
||||
@@ -53,7 +53,6 @@ extension _HomeScreenInteractions on _HomeScreenState {
|
||||
});
|
||||
|
||||
try {
|
||||
_trackClick('send_message');
|
||||
await _chatBloc.sendMessage(content, images: images);
|
||||
} finally {
|
||||
if (mounted) {
|
||||
|
||||
@@ -3,7 +3,6 @@ import 'core/config/env.dart';
|
||||
import 'core/logging/logger.dart';
|
||||
import 'core/logging/log_service.dart';
|
||||
import 'core/logging/error_handler.dart';
|
||||
import 'core/analytics/tracker.dart';
|
||||
import 'app/di/injection.dart';
|
||||
import 'app/app.dart';
|
||||
|
||||
@@ -18,11 +17,6 @@ void main() async {
|
||||
await configureDependencies();
|
||||
await Env.init();
|
||||
|
||||
await AnalyticsTracker.init(
|
||||
endpoint: Env.analyticsEndpoint,
|
||||
deviceId: Env.deviceId,
|
||||
);
|
||||
|
||||
getLogger(
|
||||
'app',
|
||||
).info(message: 'App starting...', extra: {'version': Env.version});
|
||||
|
||||
Reference in New Issue
Block a user