Skip to content

Commit

Permalink
Merge pull request #3 from grahamsmith/firebase_fixes
Browse files Browse the repository at this point in the history
Firebase and other fixes
  • Loading branch information
grahamsmith authored Aug 23, 2021
2 parents 6c92fb0 + 6073680 commit 9404c56
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 40 deletions.
4 changes: 2 additions & 2 deletions example/lib/MyExampleAnalytics/example_analytics_vendor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ class ExampleAnalyticsVendor extends AnalyticsVendor {
ExampleAnalyticsVendor() : super('ExampleAnalytics');

@override
void init() {
Future<void> init() async {
print('ExampleAnalytics has run init()');
}

@override
void handleAction(AnalyticsAction action) {
Future<void> handleAction(AnalyticsAction action) async {
if (action is TrackEvent) {
print('TrackEvent: ${action.eventName} with ${action.parameters}');
}
Expand Down
2 changes: 1 addition & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class MyApp extends StatelessWidget {

class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key) {
AnalyticsX().invokeAction(SetScreen('HomePage'));
AnalyticsX().invokeAction(SetScreen('HomePage', ''));
}

final String title;
Expand Down
7 changes: 7 additions & 0 deletions lib/actions/set_analytics_collection_enabled.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:analyticsx/analytics_action.dart';

class SetAnalyticsCollectionEnabled extends AnalyticsAction {
final bool enabled;

SetAnalyticsCollectionEnabled({required this.enabled});
}
3 changes: 2 additions & 1 deletion lib/actions/set_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:analyticsx/analytics_action.dart';

class SetScreen extends AnalyticsAction {
final String screenName;
final String screenClassOverride;

SetScreen(this.screenName);
SetScreen(this.screenName, this.screenClassOverride);
}
7 changes: 7 additions & 0 deletions lib/actions/set_user_id.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:analyticsx/analytics_action.dart';

class SetUserId extends AnalyticsAction {
final String userId;

SetUserId(this.userId);
}
8 changes: 8 additions & 0 deletions lib/actions/set_user_property.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:analyticsx/analytics_action.dart';

class SetUserProperty extends AnalyticsAction {
final String propertyName;
final String propertyValue;

SetUserProperty(this.propertyName, this.propertyValue);
}
2 changes: 1 addition & 1 deletion lib/actions/track_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:analyticsx/analytics_action.dart';

class TrackEvent extends AnalyticsAction {
final String eventName;
final Map<String, String> parameters;
final Map<String, dynamic> parameters;

TrackEvent(this.eventName, this.parameters);
}
4 changes: 2 additions & 2 deletions lib/analytics_vendor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ abstract class AnalyticsVendor {

AnalyticsVendor(this.id);

void init();
void handleAction(AnalyticsAction action);
Future<void> init();
Future<void> handleAction(AnalyticsAction action);
}
15 changes: 6 additions & 9 deletions lib/analytics_x.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,22 @@ class AnalyticsX {

AnalyticsX._internal();

void init(List<AnalyticsVendor> vendors) {
final newVendors = List.from(vendors).toSet().difference(_vendors.toSet()).toList();
Future<void> init(List<AnalyticsVendor> vendors) async {
final newVendors = List<AnalyticsVendor>.from(vendors)..removeWhere((v) => _vendors.contains(v));

if (newVendors.isEmpty) {
return;
}

for (final vendor in newVendors) {
vendor.init();
}
await Future.wait(newVendors.map((vendor) => vendor.init())); //Do all the inits in parallel

_vendors.addAll(List.from(newVendors));
}

void invokeAction(AnalyticsAction action, [List<String> vendorIds = ALL]) {
Future<void> invokeAction(AnalyticsAction action, [List<String> vendorIds = ALL]) async {
final List<AnalyticsVendor> vendorsToUse = _filterVendors(vendorIds);

for (final vendor in vendorsToUse) {
vendor.handleAction(action);
}
await Future.wait(vendorsToUse.map((vendor) => vendor.handleAction(action))); //Do all the actions in parallel
}

List<AnalyticsVendor> _filterVendors(List<String> vendorIds) {
Expand Down
26 changes: 22 additions & 4 deletions lib/vendors/firebase.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'package:analyticsx/actions/set_analytics_collection_enabled.dart';
import 'package:analyticsx/actions/set_screen.dart';
import 'package:analyticsx/actions/set_user_id.dart';
import 'package:analyticsx/actions/set_user_property.dart';
import 'package:analyticsx/actions/track_event.dart';
import 'package:analyticsx/analytics_action.dart';
import 'package:analyticsx/analytics_vendor.dart';
Expand All @@ -10,18 +13,33 @@ class Firebase extends AnalyticsVendor {
Firebase() : super('Firebase');

@override
void init() {
Future<void> init() async {
//nothing for Firebase;
}

@override
void handleAction(AnalyticsAction action) {
Future<void> handleAction(AnalyticsAction action) async {
if (action is TrackEvent) {
analytics.logEvent(name: action.eventName, parameters: action.parameters);
await analytics.logEvent(name: action.eventName, parameters: action.parameters);
}

if (action is SetScreen) {
analytics.setCurrentScreen(screenName: action.screenName);
await analytics.setCurrentScreen(
screenName: action.screenName,
screenClassOverride: action.screenClassOverride,
);
}

if (action is SetUserId) {
await analytics.setUserId(action.userId);
}

if (action is SetUserProperty) {
await analytics.setUserProperty(name: action.propertyName, value: action.propertyValue);
}

if (action is SetAnalyticsCollectionEnabled) {
await analytics.setAnalyticsCollectionEnabled(action.enabled);
}
}
}
46 changes: 26 additions & 20 deletions test/analytics_x_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class FakeVendor extends AnalyticsVendor {
List<String> handleActionWasCalledWith = [];

@override
void handleAction(AnalyticsAction action) {
Future<void> handleAction(AnalyticsAction action) async {
handleActionWasCalledXTimes++;
if (action is FakeAction) {
handleActionWasCalledWith.add(action.fakeProperty);
}
}

@override
void init() {
Future<void> init() async {
initWasCalledXTimes++;
}
}
Expand All @@ -47,49 +47,55 @@ void main() {
ax.uninit();
});

test('AnalyticsX is (probably) a singleton', () {
test('AnalyticsX is (probably) a singleton', () async {
// Whilst identical(..) proves that both variables reference the same object, you can't definitively prove that it's
// a singleton this way, since two identical strings are optimised to use the same reference
final ax2 = AnalyticsX();
expect(identical(ax, ax2), true);
});

test('Vendor init is called once when Analytics init is called once', () {
ax.init([fakeVendor]);
test('Vendor init is called once when Analytics init is called once', () async {
await ax.init([fakeVendor]);
expect(fakeVendor.initWasCalledXTimes, 1);
});

test('Vendor init is called once when Analytics init is called twice', () {
ax.init([fakeVendor]);
ax.init([fakeVendor]);
test('Vendor init is called once when Analytics init is called twice', () async {
await ax.init([fakeVendor]);
await ax.init([fakeVendor]);
expect(fakeVendor.initWasCalledXTimes, 1);
});

test('First vendor init is not called again when Analytics init is called with second vendor', () {
ax.init([fakeVendor]);
test('First vendor init is not called again when Analytics init is called with second vendor', () async {
await ax.init([fakeVendor]);
final fakeVendor2 = FakeVendor2();
ax.init([fakeVendor2]);
await ax.init([fakeVendor2]);
expect(fakeVendor.initWasCalledXTimes, 1);
});

test('Second vendor init is called when Analytics init is called with second vendor', () {
ax.init([fakeVendor]);
test('Second vendor init is called when Analytics init is called with second vendor', () async {
await ax.init([fakeVendor]);
final fakeVendor2 = FakeVendor2();
ax.init([fakeVendor2]);
await ax.init([fakeVendor2]);
expect(fakeVendor2.initWasCalledXTimes, 1);
});

test('Vendor handleAction is called once when invokeAction is called once', () {
ax.init([fakeVendor]);
ax.invokeAction(FakeAction("potato"));
test('Vendor handleAction is called once when invokeAction is called once', () async {
await ax.init([fakeVendor]);
await ax.invokeAction(FakeAction("potato"));
expect(fakeVendor.handleActionWasCalledXTimes, 1);
});

test('Correct vendor handleActions are called when invokeAction is called with vendorIds', () {
test('Correct vendor handleActions are called when invokeAction is called with vendorIds', () async {
final fakeVendor2 = FakeVendor2();
ax.init([fakeVendor, fakeVendor2]);
ax.invokeAction(FakeAction("potato"), [fakeVendor2.id]);
await ax.init([fakeVendor, fakeVendor2]);
await ax.invokeAction(FakeAction("potato"), [fakeVendor2.id]);
expect(fakeVendor.handleActionWasCalledXTimes, 0);
expect(fakeVendor2.handleActionWasCalledXTimes, 1);
});

test('Vendor handleAction is not called when invokeAction is called with non-existent vendorId', () async {
await ax.init([fakeVendor]);
await ax.invokeAction(FakeAction("potato"), ['NonExistentVendorId']);
expect(fakeVendor.handleActionWasCalledXTimes, 0);
});
}

0 comments on commit 9404c56

Please sign in to comment.