Files
GitJournal/lib/analytics/analytics.dart
Vishesh Handa 17dd93451f Remove firebase analytics
Sadly, even when firebase analytics is disabled, it still sends some
data to Google's servers and there seems to be no way to disable it.
GitJournal gives its users an option to disable all analytics, which
clearly can't be implemented as long as we use Firebase.

Therefore there are 2 options -
1. Remove the option of disabling all analytics
2. Remove firebase analytics.

I'm choosing option (2), as it seems wrong to remove the option to
disable analytics, as I know a number of users who have disabled
analytics.

Currently I'm mostly using analytics to measure how well the marketting
is doing, and to see which settings are being used. Disabling the
analytics would make this much much harder, but I guess it's a greater
push for me to find an alternative / create one.

Fixes #506
Related to #105
2021-06-07 12:21:41 +02:00

290 lines
7.4 KiB
Dart

import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:device_info/device_info.dart';
import 'package:gitjournal/app.dart';
import 'package:gitjournal/error_reporting.dart';
import 'package:gitjournal/utils/logger.dart';
Analytics getAnalytics() {
return JournalApp.analytics;
}
enum Event {
NoteAdded,
NoteUpdated,
NoteDeleted,
NoteUndoDeleted,
NoteRenamed,
NoteMoved,
FileRenamed,
FolderAdded,
FolderDeleted,
FolderRenamed,
FolderConfigUpdated,
RepoSynced,
DrawerSetupGitHost,
DrawerShare,
DrawerRate,
DrawerFeedback,
DrawerBugReport,
DrawerSettings,
PurchaseScreenOpen,
PurchaseScreenClose,
PurchaseScreenThankYou,
GitHostSetupError,
GitHostSetupComplete,
GitHostSetupGitCloneError,
GitHostSetupButtonClick,
Settings,
FeatureTimelineGithubClicked,
AppFirstOpen,
AppUpdate,
// FIXME: Add os_update
/*
Firebase Automatic Events:
app_update:
previous_app_version
first_open
in_app_purchase
screen_view
session_start
user_engagement
*/
}
String _eventToString(Event e) {
switch (e) {
case Event.NoteAdded:
return "note_added";
case Event.NoteUpdated:
return "note_updated";
case Event.NoteDeleted:
return "note_deleted";
case Event.NoteUndoDeleted:
return "note_undo_deleted";
case Event.NoteRenamed:
return "note_renamed";
case Event.NoteMoved:
return "note_moved";
case Event.FileRenamed:
return "file_renamed";
case Event.FolderAdded:
return "folder_added";
case Event.FolderDeleted:
return "folder_deleted";
case Event.FolderRenamed:
return "folder_renamed";
case Event.FolderConfigUpdated:
return "folder_config_updated";
case Event.RepoSynced:
return "repo_synced";
case Event.DrawerSetupGitHost:
return "drawer_setupGitHost";
case Event.DrawerShare:
return "drawer_share";
case Event.DrawerRate:
return "drawer_rate";
case Event.DrawerFeedback:
return "drawer_feedback";
case Event.DrawerBugReport:
return "drawer_bugreport";
case Event.DrawerSettings:
return "drawer_settings";
case Event.PurchaseScreenOpen:
return "purchase_screen_open";
case Event.PurchaseScreenClose:
return "purchase_screen_close";
case Event.PurchaseScreenThankYou:
return "purchase_screen_thank_you";
case Event.GitHostSetupError:
return "githostsetup_error";
case Event.GitHostSetupComplete:
return "onboarding_complete";
case Event.GitHostSetupGitCloneError:
return "onboarding_gitClone_error";
case Event.GitHostSetupButtonClick:
return "githostsetup_button_click";
case Event.Settings:
return "settings";
case Event.FeatureTimelineGithubClicked:
return "feature_timeline_github_clicked";
case Event.AppFirstOpen:
return "gj_first_open";
case Event.AppUpdate:
return "gj_app_update";
}
}
class Analytics {
// var firebase = FirebaseAnalytics();
bool enabled = false;
Future<void> log({
required Event e,
Map<String, String> parameters = const {},
}) async {
String name = _eventToString(e);
if (enabled) {
if (Platform.isAndroid || Platform.isIOS) {
// await firebase.logEvent(name: name, parameters: parameters);
}
}
captureErrorBreadcrumb(name: name, parameters: parameters);
}
Future<void> setAnalyticsCollectionEnabled(bool enabled) async {
this.enabled = enabled;
if (Platform.isAndroid || Platform.isIOS) {
// await firebase.setAnalyticsCollectionEnabled(enabled);
}
}
Future<void> setCurrentScreen({required String screenName}) async {
if (!enabled) {
return;
}
if (Platform.isAndroid || Platform.isIOS) {
// await firebase.setCurrentScreen(screenName: screenName);
}
}
Future<void> setUserProperty({
required String name,
required String value,
}) async {
if (!enabled) {
return;
}
if (Platform.isAndroid || Platform.isIOS) {
// await firebase.setUserProperty(name: name, value: value);
}
}
}
void logEvent(Event event, {Map<String, String> parameters = const {}}) {
getAnalytics().log(e: event, parameters: parameters);
Log.d("$event", props: parameters);
}
class AnalyticsRouteObserver extends RouteObserver<PageRoute<dynamic>> {
void _sendScreenView(PageRoute<dynamic> route) async {
var screenName = route.settings.name;
if (route.runtimeType.toString().startsWith("_SearchPageRoute")) {
screenName = "/search";
}
if (screenName == null) {
screenName = 'Unknown';
return;
}
try {
await getAnalytics().setCurrentScreen(screenName: screenName);
} catch (e, stackTrace) {
Log.e("AnalyticsRouteObserver", ex: e, stacktrace: stackTrace);
}
}
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
super.didPush(route, previousRoute);
if (route is PageRoute) {
_sendScreenView(route);
} else {
// print("route in not a PageRoute! $route");
}
}
@override
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
if (newRoute is PageRoute) {
_sendScreenView(newRoute);
} else {
// print("newRoute in not a PageRoute! $newRoute");
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
super.didPop(route, previousRoute);
if (previousRoute is PageRoute && route is PageRoute) {
_sendScreenView(previousRoute);
} else {
// print("previousRoute in not a PageRoute! $previousRoute");
// print("route in not a PageRoute! $route");
}
}
}
// This should be provided by device_info
Map<String, dynamic> readAndroidBuildData(AndroidDeviceInfo build) {
return <String, dynamic>{
'version.securityPatch': build.version.securityPatch,
'version.sdkInt': build.version.sdkInt,
'version.release': build.version.release,
'version.previewSdkInt': build.version.previewSdkInt,
'version.incremental': build.version.incremental,
'version.codename': build.version.codename,
'version.baseOS': build.version.baseOS,
'board': build.board,
'bootloader': build.bootloader,
'brand': build.brand,
'device': build.device,
'display': build.display,
'fingerprint': build.fingerprint,
'hardware': build.hardware,
'host': build.host,
'id': build.id,
'manufacturer': build.manufacturer,
'model': build.model,
'product': build.product,
'supported32BitAbis': build.supported32BitAbis,
'supported64BitAbis': build.supported64BitAbis,
'supportedAbis': build.supportedAbis,
'tags': build.tags,
'type': build.type,
'isPhysicalDevice': build.isPhysicalDevice,
'androidId': build.androidId,
'systemFeatures': build.systemFeatures,
};
}
Map<String, dynamic> readIosDeviceInfo(IosDeviceInfo data) {
return <String, dynamic>{
'name': data.name,
'systemName': data.systemName,
'systemVersion': data.systemVersion,
'model': data.model,
'localizedModel': data.localizedModel,
'identifierForVendor': data.identifierForVendor,
'isPhysicalDevice': data.isPhysicalDevice,
'utsname.sysname:': data.utsname.sysname,
'utsname.nodename:': data.utsname.nodename,
'utsname.release:': data.utsname.release,
'utsname.version:': data.utsname.version,
'utsname.machine:': data.utsname.machine,
};
}