Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable dependency injection for CustomerIO #85

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions apps/amiapp_flutter/lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ class _AmiAppState extends State<AmiApp> {
onLogin: (user) {
_auth.login(user).then((signedIn) {
if (signedIn) {
CustomerIO.identify(identifier: user.email, attributes: {
CustomerIO.instance
.identify(identifier: user.email, attributes: {
"first_name": user.displayName,
"email": user.email,
"is_guest": user.isGuest,
Expand Down Expand Up @@ -216,14 +217,14 @@ class _AmiAppState extends State<AmiApp> {
if (_customerIOSDK.sdkConfig?.screenTrackingEnabled == true) {
final Screen? screen = _router.location.toAppScreen();
if (screen != null) {
CustomerIO.screen(name: screen.name);
CustomerIO.instance.screen(name: screen.name);
}
}
}

void _handleAuthStateChanged() {
if (_auth.signedIn == false) {
CustomerIO.clearIdentify();
CustomerIO.instance.clearIdentify();
_auth.clearUserState();
}
}
Expand Down
2 changes: 1 addition & 1 deletion apps/amiapp_flutter/lib/src/customer_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class CustomerIOSDK extends ChangeNotifier {
} else {
logLevel = CioLogLevel.debug;
}
return CustomerIO.initialize(
return CustomerIO.instance.initialize(
config: CustomerIOConfig(
siteId: _sdkConfig?.siteId ?? '',
apiKey: _sdkConfig?.apiKey ?? '',
Expand Down
8 changes: 4 additions & 4 deletions apps/amiapp_flutter/lib/src/screens/attributes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -155,12 +155,12 @@ class _AttributesScreenState extends State<AttributesScreen> {
};
switch (widget._attributeType) {
case _attributeTypeDevice:
CustomerIO.setDeviceAttributes(
attributes: attributes);
CustomerIO.instance
.setDeviceAttributes(attributes: attributes);
break;
case _attributeTypeProfile:
CustomerIO.setProfileAttributes(
attributes: attributes);
CustomerIO.instance
.setProfileAttributes(attributes: attributes);
break;
}
_onEventTracked();
Expand Down
8 changes: 4 additions & 4 deletions apps/amiapp_flutter/lib/src/screens/dashboard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
.then((value) => setState(() => _buildInfo = value));

inAppMessageStreamSubscription =
CustomerIO.subscribeToInAppEventListener(handleInAppEvent);
CustomerIO.instance.subscribeToInAppEventListener(handleInAppEvent);
super.initState();
}

Expand Down Expand Up @@ -89,7 +89,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
};
attributes.addAll(arguments);

CustomerIO.track(
CustomerIO.instance.track(
name: 'In-App Event',
attributes: attributes,
);
Expand Down Expand Up @@ -152,9 +152,9 @@ class _ActionList extends StatelessWidget {
final eventName = event.key;
final attributes = event.value;
if (attributes == null) {
CustomerIO.track(name: eventName);
CustomerIO.instance.track(name: eventName);
} else {
CustomerIO.track(name: eventName, attributes: attributes);
CustomerIO.instance.track(name: eventName, attributes: attributes);
}
context.showSnackBar('Event sent successfully');
}
Expand Down
2 changes: 1 addition & 1 deletion apps/amiapp_flutter/lib/src/screens/events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class _CustomEventScreenState extends State<CustomEventScreen> {
attributes = propertyName.isEmpty
? {}
: {propertyName: _propertyValueController.text};
CustomerIO.track(
CustomerIO.instance.track(
name: _eventNameController.text,
attributes: attributes);
_onEventTracked();
Expand Down
27 changes: 15 additions & 12 deletions lib/customer_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import 'messaging_push/platform_interface.dart';
class CustomerIO {
const CustomerIO._();

// Singleton instance
static const CustomerIO instance = CustomerIO._();

static CustomerIOPlatform get _customerIO => CustomerIOPlatform.instance;

static CustomerIOMessagingPushPlatform get _customerIOMessagingPush =>
Expand All @@ -21,7 +24,7 @@ class CustomerIO {
/// To initialize the plugin
///
/// @param config includes required and optional configs etc
static Future<void> initialize({
Future<void> initialize({
required CustomerIOConfig config,
}) {
return _customerIO.initialize(config: config);
Expand All @@ -34,7 +37,7 @@ class CustomerIO {
///
/// @param identifier unique identifier for a profile
/// @param attributes (Optional) params to set profile attributes
static void identify(
void identify(
{required String identifier,
Map<String, dynamic> attributes = const {}}) {
return _customerIO.identify(identifier: identifier, attributes: attributes);
Expand All @@ -44,7 +47,7 @@ class CustomerIO {
///
/// If a profile exists, clearIdentify will stop identifying the profile.
/// If no profile exists, request to clearIdentify will be ignored.
static void clearIdentify() {
void clearIdentify() {
_customerIO.clearIdentify();
}

Expand All @@ -53,13 +56,13 @@ class CustomerIO {
///
/// @param name event name to be tracked
/// @param attributes (Optional) params to be sent with event
static void track(
void track(
{required String name, Map<String, dynamic> attributes = const {}}) {
return _customerIO.track(name: name, attributes: attributes);
}

/// Track a push metric
static void trackMetric(
void trackMetric(
{required String deliveryID,
required String deviceToken,
required MetricEvent event}) {
Expand All @@ -69,15 +72,15 @@ class CustomerIO {

/// Register a new device token with Customer.io, associated with the current active customer. If there
/// is no active customer, this will fail to register the device
static void registerDeviceToken({required String deviceToken}) {
void registerDeviceToken({required String deviceToken}) {
return _customerIO.registerDeviceToken(deviceToken: deviceToken);
}

/// Track screen events to record the screens a user visits
///
/// @param name name of the screen user visited
/// @param attributes (Optional) params to be sent with event
static void screen(
void screen(
{required String name, Map<String, dynamic> attributes = const {}}) {
return _customerIO.screen(name: name, attributes: attributes);
}
Expand All @@ -86,15 +89,15 @@ class CustomerIO {
/// such as app preferences, timezone etc
///
/// @param attributes device attributes
static void setDeviceAttributes({required Map<String, dynamic> attributes}) {
void setDeviceAttributes({required Map<String, dynamic> attributes}) {
return _customerIO.setDeviceAttributes(attributes: attributes);
}

/// Set custom user profile information such as user preference, specific
/// user actions etc
///
/// @param attributes additional attributes for a user profile
static void setProfileAttributes({required Map<String, dynamic> attributes}) {
void setProfileAttributes({required Map<String, dynamic> attributes}) {
return _customerIO.setProfileAttributes(attributes: attributes);
}

Expand All @@ -104,16 +107,16 @@ class CustomerIO {
/// The callback returns [InAppEvent].
///
/// Returns a [StreamSubscription] that can be used to subscribe/unsubscribe from the event listener.
static StreamSubscription subscribeToInAppEventListener(
StreamSubscription subscribeToInAppEventListener(
void Function(InAppEvent) onEvent) {
return _customerIO.subscribeToInAppEventListener(onEvent);
}

static CustomerIOMessagingPushPlatform messagingPush() {
CustomerIOMessagingPushPlatform messagingPush() {
return _customerIOMessagingPush;
}

static CustomerIOMessagingInAppPlatform messagingInApp() {
CustomerIOMessagingInAppPlatform messagingInApp() {
return _customerIOMessagingInApp;
}
}
44 changes: 25 additions & 19 deletions test/customer_io_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void main() {
// initialize
test('initialize() calls platform', () async {
final config = CustomerIOConfig(siteId: '123', apiKey: '456');
await CustomerIO.initialize(config: config);
await CustomerIO.instance.initialize(config: config);

verify(mockPlatform.initialize(config: config)).called(1);
});
Expand All @@ -50,7 +50,7 @@ void main() {
apiKey: '456',
region: Region.eu,
autoTrackPushEvents: false);
await CustomerIO.initialize(config: givenConfig);
await CustomerIO.instance.initialize(config: givenConfig);
expect(
verify(mockPlatform.initialize(config: captureAnyNamed("config")))
.captured
Expand All @@ -62,8 +62,8 @@ void main() {
test('identify() calls platform', () {
const givenIdentifier = '[email protected]';
final givenAttributes = {'name': 'John Doe'};
CustomerIO.identify(
identifier: givenIdentifier, attributes: givenAttributes);
CustomerIO.instance
.identify(identifier: givenIdentifier, attributes: givenAttributes);

verify(mockPlatform.identify(
identifier: givenIdentifier, attributes: givenAttributes))
Expand All @@ -73,8 +73,8 @@ void main() {
test('identify() correct arguments are passed', () {
const givenIdentifier = '[email protected]';
final givenAttributes = {'name': 'John Doe'};
CustomerIO.identify(
identifier: givenIdentifier, attributes: givenAttributes);
CustomerIO.instance
.identify(identifier: givenIdentifier, attributes: givenAttributes);
expect(
verify(mockPlatform.identify(
identifier: captureAnyNamed("identifier"),
Expand All @@ -85,22 +85,22 @@ void main() {

// clearIdentify
test('clearIdentify() calls platform', () {
CustomerIO.clearIdentify();
CustomerIO.instance.clearIdentify();
verify(mockPlatform.clearIdentify()).called(1);
});

// track
test('track() calls platform', () {
const name = 'itemAddedToCart';
final attributes = {'item': 'shoes'};
CustomerIO.track(name: name, attributes: attributes);
CustomerIO.instance.track(name: name, attributes: attributes);
verify(mockPlatform.track(name: name, attributes: attributes)).called(1);
});

test('track() correct arguments are passed', () {
const name = 'itemAddedToCart';
final givenAttributes = {'name': 'John Doe'};
CustomerIO.track(name: name, attributes: givenAttributes);
CustomerIO.instance.track(name: name, attributes: givenAttributes);
expect(
verify(mockPlatform.track(
name: captureAnyNamed("name"),
Expand All @@ -114,7 +114,7 @@ void main() {
const deliveryID = '123';
const deviceToken = 'abc';
const event = MetricEvent.opened;
CustomerIO.trackMetric(
CustomerIO.instance.trackMetric(
deliveryID: deliveryID, deviceToken: deviceToken, event: event);
verify(mockPlatform.trackMetric(
deliveryID: deliveryID, deviceToken: deviceToken, event: event))
Expand All @@ -125,7 +125,7 @@ void main() {
const deliveryID = '123';
const deviceToken = 'abc';
const event = MetricEvent.opened;
CustomerIO.trackMetric(
CustomerIO.instance.trackMetric(
deliveryID: deliveryID, deviceToken: deviceToken, event: event);
expect(
verify(mockPlatform.trackMetric(
Expand All @@ -139,14 +139,14 @@ void main() {
// registerDeviceToken
test('registerDeviceToken() calls platform', () {
const deviceToken = 'token';
CustomerIO.registerDeviceToken(deviceToken: deviceToken);
CustomerIO.instance.registerDeviceToken(deviceToken: deviceToken);
verify(mockPlatform.registerDeviceToken(deviceToken: deviceToken))
.called(1);
});

test('registerDeviceToken() correct arguments are passed', () {
const deviceToken = 'token';
CustomerIO.registerDeviceToken(deviceToken: deviceToken);
CustomerIO.instance.registerDeviceToken(deviceToken: deviceToken);
expect(
verify(mockPlatform.registerDeviceToken(
deviceToken: captureAnyNamed("deviceToken")))
Expand All @@ -159,15 +159,15 @@ void main() {
test('screen() calls platform', () {
const name = 'home';
final givenAttributes = {'user': 'John Doe'};
CustomerIO.screen(name: name, attributes: givenAttributes);
CustomerIO.instance.screen(name: name, attributes: givenAttributes);
verify(mockPlatform.screen(name: name, attributes: givenAttributes))
.called(1);
});

test('screen() correct arguments are passed', () {
const name = 'itemAddedToCart';
final givenAttributes = {'name': 'John Doe'};
CustomerIO.screen(name: name, attributes: givenAttributes);
CustomerIO.instance.screen(name: name, attributes: givenAttributes);
expect(
verify(mockPlatform.screen(
name: captureAnyNamed("name"),
Expand All @@ -179,14 +179,14 @@ void main() {
// setDeviceAttributes
test('setDeviceAttributes() calls platform', () {
final givenAttributes = {'area': 'US'};
CustomerIO.setDeviceAttributes(attributes: givenAttributes);
CustomerIO.instance.setDeviceAttributes(attributes: givenAttributes);
verify(mockPlatform.setDeviceAttributes(attributes: givenAttributes))
.called(1);
});

test('setDeviceAttributes() correct arguments are passed', () {
final givenAttributes = {'area': 'US'};
CustomerIO.setDeviceAttributes(attributes: givenAttributes);
CustomerIO.instance.setDeviceAttributes(attributes: givenAttributes);
expect(
verify(mockPlatform.setDeviceAttributes(
attributes: captureAnyNamed("attributes")))
Expand All @@ -198,14 +198,14 @@ void main() {
// setProfileAttributes
test('setProfileAttributes() calls platform', () {
final givenAttributes = {'age': 10};
CustomerIO.setProfileAttributes(attributes: givenAttributes);
CustomerIO.instance.setProfileAttributes(attributes: givenAttributes);
verify(mockPlatform.setProfileAttributes(attributes: givenAttributes))
.called(1);
});

test('setProfileAttributes() correct arguments are passed', () {
final givenAttributes = {'age': 10};
CustomerIO.setProfileAttributes(attributes: givenAttributes);
CustomerIO.instance.setProfileAttributes(attributes: givenAttributes);
expect(
verify(mockPlatform.setProfileAttributes(
attributes: captureAnyNamed("attributes")))
Expand All @@ -214,4 +214,10 @@ void main() {
givenAttributes);
});
});

test('Singleton instance should be initialized once', () {
var firstInstance = CustomerIO.instance;
var secondInstance = CustomerIO.instance;
expect(firstInstance, secondInstance);
});
}