Skip to content

Commit 724940c

Browse files
authored
Merge pull request #3215 from numbersprotocol/feature-track-new-app-users-shutter-click
Feature track new app users shutter click
2 parents 335252e + 4bb6b6e commit 724940c

File tree

4 files changed

+63
-2
lines changed

4 files changed

+63
-2
lines changed

src/app/features/home/custom-camera/custom-camera.page.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
throttleTime,
3131
} from 'rxjs/operators';
3232
import { AndroidBackButtonService } from '../../../shared/android-back-button/android-back-button.service';
33+
import { AppsFlyerService } from '../../../shared/apps-flyer/apps-flyer.service';
3334
import {
3435
CaptureTabSegments,
3536
CaptureTabService,
@@ -117,7 +118,8 @@ export class CustomCameraPage implements OnInit, OnDestroy {
117118
private readonly ref: ChangeDetectorRef,
118119
private readonly androidBackButtonService: AndroidBackButtonService,
119120
private readonly navController: NavController,
120-
private readonly platform: Platform
121+
private readonly platform: Platform,
122+
private readonly appsflyerService: AppsFlyerService
121123
) {}
122124

123125
ngOnInit() {
@@ -315,13 +317,15 @@ export class CustomCameraPage implements OnInit, OnDestroy {
315317
if (this.mode$.value === 'photo') {
316318
this.flashCameraScreen();
317319
this.customCameraService.takePhoto();
320+
this.appsflyerService.logCameraShutterEvent();
318321
this.userGuideService.setHasCapturedPhotoWithCustomCamera(true);
319322
} else {
320323
if (this.isRecording$.value === true) {
321324
this.isRecording$.next(false);
322325
} else {
323326
this.isRecording$.next(true);
324327
this.customCameraService.startRecord();
328+
this.appsflyerService.logCameraShutterEvent();
325329
const intervalRate = 50;
326330
combineLatest([this.isRecording$, interval(intervalRate)])
327331
.pipe(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Enum representing custom event names for AppsFlyer in-app events.
3+
*
4+
* While it's recommended to use predefined event names, custom event names are easier for QA
5+
* and marketing teams to understand and filter out in the AppsFlyer dashboard. Refer to the Asana
6+
* comment https://app.asana.com/0/0/1206618451736620/1206636906894474/f for more details.
7+
*
8+
* Every custom event name should be prefixed with 'ccam_' which stands for Capture Cam. This prefix
9+
* helps to distinguish between predefined AppsFlyer event names such as 'af_level_achieved', etc.
10+
*/
11+
export enum CCamCustomEventType {
12+
CCAM_TRY_CLICK_CAMERA_SHUTTER = 'ccam_try_click_camera_shutter',
13+
}

src/app/shared/apps-flyer/apps-flyer.service.spec.ts

+19
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { TestBed, waitForAsync } from '@angular/core/testing';
22
import { Platform } from '@ionic/angular';
33
import { SharedTestingModule } from '../shared-testing.module';
44

5+
import { AFEvent } from 'appsflyer-capacitor-plugin';
6+
import { CCamCustomEventType } from './apps-flyer-enums';
57
import { AppsFlyerService } from './apps-flyer.service';
68

79
describe('AppsFlyerService', () => {
@@ -32,4 +34,21 @@ describe('AppsFlyerService', () => {
3234
it('should be created', () => {
3335
expect(service).toBeTruthy();
3436
});
37+
38+
it('should log camera shutter event through Appsflyer.logEvent method', async () => {
39+
const expectedEvent: AFEvent = {
40+
eventName: CCamCustomEventType.CCAM_TRY_CLICK_CAMERA_SHUTTER,
41+
};
42+
// NOTE: We're accessing a private method here for testing purposes only.
43+
// TypeScript doesn't enforce private/protected visibility at runtime, only at compile time.
44+
// This is generally not recommended as it can lead to fragile tests and breaks encapsulation.
45+
// However, in this case, we need to ensure that the private method 'logEvent' is called with
46+
// the correct parameters.
47+
const logEventSpy = spyOn(service as any, 'logEvent');
48+
49+
await service.logCameraShutterEvent();
50+
51+
expect(logEventSpy).toHaveBeenCalledWith(expectedEvent);
52+
expect(logEventSpy).toHaveBeenCalledTimes(1);
53+
});
3554
});

src/app/shared/apps-flyer/apps-flyer.service.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { Injectable } from '@angular/core';
22
import { AdvertisingId } from '@capacitor-community/advertising-id';
33
import { Capacitor } from '@capacitor/core';
44
import { Platform } from '@ionic/angular';
5-
import { AFInit, AppsFlyer } from 'appsflyer-capacitor-plugin';
5+
import { AFEvent, AFInit, AppsFlyer } from 'appsflyer-capacitor-plugin';
66
import { APPS_FLYER_DEV_KEY } from '../dia-backend/secret';
7+
import { CCamCustomEventType } from './apps-flyer-enums';
78

89
@Injectable({
910
providedIn: 'root',
@@ -55,4 +56,28 @@ export class AppsFlyerService {
5556
const isTruthy = Boolean(APPS_FLYER_DEV_KEY);
5657
return isTruthy && Capacitor.isNativePlatform();
5758
}
59+
60+
// eslint-disable-next-line class-methods-use-this
61+
private async logEvent(event: AFEvent) {
62+
try {
63+
await AppsFlyer.logEvent(event);
64+
} catch (error) {
65+
// TODO: Report error to Crashlytics or any other error reporting service if available.
66+
}
67+
}
68+
69+
/**
70+
* Logs a camera shutter event to AppsFlyer.
71+
*
72+
* This event is logged when the user clicks the camera shutter button to take a photo or video.
73+
* It does not necessarily indicate the registering of a photo or video, only the act of clicking
74+
* the shutter button.
75+
*
76+
*/
77+
async logCameraShutterEvent() {
78+
const eventData: AFEvent = {
79+
eventName: CCamCustomEventType.CCAM_TRY_CLICK_CAMERA_SHUTTER,
80+
};
81+
await this.logEvent(eventData);
82+
}
5883
}

0 commit comments

Comments
 (0)