From f08573f8a814e6e650c018eda0dfd40a48d77710 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 3 Aug 2023 18:47:30 +0800 Subject: [PATCH 01/18] Revert "feat(ci): Update GitHub Actions workflow" This reverts commit 91a457c87c7ede48d591fa3c809509cda726b987. --- .github/workflows/test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 16199a750..118737525 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,8 @@ name: test -on: [push, pull_request] +on: + push: + branches: [master, develop, 'feature-*', 'fix-*', 'hotfix-*'] jobs: lint: From 76eb5be7a94018aeb9680f64e864e0d821f86036 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Thu, 3 Aug 2023 18:57:13 +0800 Subject: [PATCH 02/18] fix(test.yml): Update branch triggers to match latest changes This commit updates the branch triggers in the 'test.yml' file to align with the latest changes in our development process. The 'develop' branch has been deprecated, and we now use 'milestone-*' branches as per the guidelines in the numbers developer guideline documentation. --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 118737525..af1a8c03b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,8 @@ name: test on: push: - branches: [master, develop, 'feature-*', 'fix-*', 'hotfix-*'] + branches: + [master, 'feature-*', 'feat-*', 'fix-*', 'hotfix-*', 'milestone-*'] jobs: lint: From 78ef1a2a8ad79d1b627362b01840cab90b55f00e Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 19 Feb 2024 17:29:02 +0800 Subject: [PATCH 03/18] WIP: Add AppsFlyer and CCam custom event enums --- src/app/shared/apps-flyer/apps-flyer-enums.ts | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/app/shared/apps-flyer/apps-flyer-enums.ts diff --git a/src/app/shared/apps-flyer/apps-flyer-enums.ts b/src/app/shared/apps-flyer/apps-flyer-enums.ts new file mode 100644 index 000000000..6a232b19d --- /dev/null +++ b/src/app/shared/apps-flyer/apps-flyer-enums.ts @@ -0,0 +1,48 @@ +/** + * Enum representing predefined event types for AppsFlyer in-app events. + * + * Note: appsflyer-capacitor-plugin does not provide these constants. + * Therefore, they are defined manually here. + * + * For a list of predefined event names, see: + * {@link https://dev.appsflyer.com/hc/docs/in-app-events-android#event-constants|AppsFlyer Predefined Event Constants}. + */ +export enum AFInAppEventType { + LEVEL_ACHIEVED = 'af_level_achieved', +} + +/** + * Enum representing predefined event parameter names for AppsFlyer in-app events. + * + * Note: appsflyer-capacitor-plugin does not provide these constants. + * Therefore, they are defined manually here. + * + * For a list of predefined event parameters, see: + * {@link https://dev.appsflyer.com/hc/docs/in-app-events-android#predefined-event-parameters|AppsFlyer Predefined Event Parameters}. + */ +export enum AFInAppEventParameterName { + /** + * The level parameter for in-app events. + * + * Levels can be determined by the type of event. For example: + * - Level 1: User clicks on the camera shutter or navigates to explore page. + * - Level 2: Actions that require more effort such as registering an asset. + * - Level 3: User executes network actions such as Mint & Share. + * + * Consult and communicate with the product manager to determine appropriate levels. + */ + LEVEL = 'af_level', + /** + * The score parameter for in-app events. + * + * Typically, this parameter is set to 0 as no decision is currently made based on 'af_score'. + * However, it can be used to assign scores to users based on their actions in the app. + * + * Consult and communicate with the product manager to determine the usage of scores. + */ + SCORE = 'af_score', +} + +export enum CCamCustomEventType { + CCAM_TRY_CLICK_CAMERA_SHUTTER = 'ccam_try_click_camera_shutter', +} From eb14916083f26f1720c43e29327e44c9e8da475a Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 19 Feb 2024 17:30:29 +0800 Subject: [PATCH 04/18] WIP: Add logCameraShutterEvent method to AppsFlyerService --- .../shared/apps-flyer/apps-flyer.service.ts | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/app/shared/apps-flyer/apps-flyer.service.ts b/src/app/shared/apps-flyer/apps-flyer.service.ts index 9177f0bfb..57edcacf4 100644 --- a/src/app/shared/apps-flyer/apps-flyer.service.ts +++ b/src/app/shared/apps-flyer/apps-flyer.service.ts @@ -2,8 +2,13 @@ import { Injectable } from '@angular/core'; import { AdvertisingId } from '@capacitor-community/advertising-id'; import { Capacitor } from '@capacitor/core'; import { Platform } from '@ionic/angular'; -import { AFInit, AppsFlyer } from 'appsflyer-capacitor-plugin'; +import { AFEvent, AFInit, AppsFlyer } from 'appsflyer-capacitor-plugin'; import { APPS_FLYER_DEV_KEY } from '../dia-backend/secret'; +import { + AFInAppEventParameterName, + AFInAppEventType, + CCamCustomEventType, +} from './apps-flyer-enums'; @Injectable({ providedIn: 'root', @@ -55,4 +60,32 @@ export class AppsFlyerService { const isTruthy = Boolean(APPS_FLYER_DEV_KEY); return isTruthy && Capacitor.isNativePlatform(); } + + private async logEvent(event: AFEvent) { + try { + await AppsFlyer.logEvent(event); + } catch (error) { + // TODO: Report error to Crashlytics or any other error reporting service if available. + } + } + + /** + * Logs a camera shutter event to AppsFlyer. + * + * This event is logged when the user clicks the camera shutter button to take a photo or video. + * It does not necessarily indicate the registering of a photo or video, only the act of clicking + * the shutter button. + * + */ + async logCameraShutterEvent() { + const eventData: AFEvent = { + eventName: AFInAppEventType.LEVEL_ACHIEVED, + eventValue: { + [AFInAppEventParameterName.LEVEL]: '1', + af_score: '0', + af_achievement_id: CCamCustomEventType.CCAM_TRY_CLICK_CAMERA_SHUTTER, + }, + }; + await this.logEvent(eventData); + } } From f306704992f82296a24dd85487e1a86e79d6632c Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 19 Feb 2024 20:42:47 +0800 Subject: [PATCH 05/18] WIP: Add test for logging camera shutter event --- .../apps-flyer/apps-flyer.service.spec.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/app/shared/apps-flyer/apps-flyer.service.spec.ts b/src/app/shared/apps-flyer/apps-flyer.service.spec.ts index 3d1f204a7..dc4ac3521 100644 --- a/src/app/shared/apps-flyer/apps-flyer.service.spec.ts +++ b/src/app/shared/apps-flyer/apps-flyer.service.spec.ts @@ -2,6 +2,7 @@ import { TestBed, waitForAsync } from '@angular/core/testing'; import { Platform } from '@ionic/angular'; import { SharedTestingModule } from '../shared-testing.module'; +import { AFEvent } from 'appsflyer-capacitor-plugin'; import { AppsFlyerService } from './apps-flyer.service'; describe('AppsFlyerService', () => { @@ -32,4 +33,26 @@ describe('AppsFlyerService', () => { it('should be created', () => { expect(service).toBeTruthy(); }); + + it('should log camera shutter event through Appsflyer.logEvent method', async () => { + const expectedEvent: AFEvent = { + eventName: 'af_level_achieved', + eventValue: { + af_level: '1', + af_score: '0', + af_achievement_id: 'ccam_try_click_camera_shutter', + }, + }; + // NOTE: We're accessing a private method here for testing purposes only. + // TypeScript doesn't enforce private/protected visibility at runtime, only at compile time. + // This is generally not recommended as it can lead to fragile tests and breaks encapsulation. + // However, in this case, we need to ensure that the private method 'logEvent' is called with + // the correct parameters. + const logEventSpy = spyOn(service as any, 'logEvent'); + + await service.logCameraShutterEvent(); + + expect(logEventSpy).toHaveBeenCalledWith(expectedEvent); + expect(logEventSpy).toHaveBeenCalledTimes(1); + }); }); From a79d995a5514ad173855b0526640b61cea2cb800 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Mon, 19 Feb 2024 20:48:24 +0800 Subject: [PATCH 06/18] feat(custom-camera): log appsflyer event when user click camera shutter --- src/app/features/home/custom-camera/custom-camera.page.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/features/home/custom-camera/custom-camera.page.ts b/src/app/features/home/custom-camera/custom-camera.page.ts index 1a604f8f3..1a2656e93 100644 --- a/src/app/features/home/custom-camera/custom-camera.page.ts +++ b/src/app/features/home/custom-camera/custom-camera.page.ts @@ -31,6 +31,7 @@ import { throttleTime, } from 'rxjs/operators'; import { AndroidBackButtonService } from '../../../shared/android-back-button/android-back-button.service'; +import { AppsFlyerService } from '../../../shared/apps-flyer/apps-flyer.service'; import { CaptureTabSegments, CaptureTabService, @@ -120,7 +121,8 @@ export class CustomCameraPage implements OnInit, OnDestroy { private readonly ref: ChangeDetectorRef, private readonly androidBackButtonService: AndroidBackButtonService, private readonly navController: NavController, - private readonly platform: Platform + private readonly platform: Platform, + private readonly appsflyerService: AppsFlyerService ) {} ngOnInit() { @@ -386,6 +388,7 @@ export class CustomCameraPage implements OnInit, OnDestroy { if (this.mode$.value === 'photo') { this.flashCameraScreen(); this.customCameraService.takePhoto(); + this.appsflyerService.logCameraShutterEvent(); this.userGuideService.setHasCapturedPhotoWithCustomCamera(true); } else { if (this.isRecording$.value === true) { @@ -393,6 +396,7 @@ export class CustomCameraPage implements OnInit, OnDestroy { } else { this.isRecording$.next(true); this.customCameraService.startRecord(); + this.appsflyerService.logCameraShutterEvent(); const intervalRate = 50; combineLatest([this.isRecording$, interval(intervalRate)]) .pipe( From 32ca6375ee1d5854c7cb1dcdadbee3d27212baeb Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 20 Feb 2024 00:07:44 +0800 Subject: [PATCH 07/18] refactor to Use custom AppsFlyer events for logCameraShutterEvent --- src/app/shared/apps-flyer/apps-flyer.service.ts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/app/shared/apps-flyer/apps-flyer.service.ts b/src/app/shared/apps-flyer/apps-flyer.service.ts index 57edcacf4..fc23ab348 100644 --- a/src/app/shared/apps-flyer/apps-flyer.service.ts +++ b/src/app/shared/apps-flyer/apps-flyer.service.ts @@ -4,11 +4,7 @@ import { Capacitor } from '@capacitor/core'; import { Platform } from '@ionic/angular'; import { AFEvent, AFInit, AppsFlyer } from 'appsflyer-capacitor-plugin'; import { APPS_FLYER_DEV_KEY } from '../dia-backend/secret'; -import { - AFInAppEventParameterName, - AFInAppEventType, - CCamCustomEventType, -} from './apps-flyer-enums'; +import { CCamCustomEventType } from './apps-flyer-enums'; @Injectable({ providedIn: 'root', @@ -79,12 +75,7 @@ export class AppsFlyerService { */ async logCameraShutterEvent() { const eventData: AFEvent = { - eventName: AFInAppEventType.LEVEL_ACHIEVED, - eventValue: { - [AFInAppEventParameterName.LEVEL]: '1', - af_score: '0', - af_achievement_id: CCamCustomEventType.CCAM_TRY_CLICK_CAMERA_SHUTTER, - }, + eventName: CCamCustomEventType.CCAM_TRY_CLICK_CAMERA_SHUTTER, }; await this.logEvent(eventData); } From da62fae324f529034c08cbf15a7147bcfd4ca60b Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 20 Feb 2024 01:14:15 +0800 Subject: [PATCH 08/18] WIP: add translations for redirect to dashboard alert --- src/assets/i18n/en-us.json | 3 ++- src/assets/i18n/zh-tw.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/assets/i18n/en-us.json b/src/assets/i18n/en-us.json index c1a437662..ba37dba41 100644 --- a/src/assets/i18n/en-us.json +++ b/src/assets/i18n/en-us.json @@ -338,7 +338,8 @@ "duplicateAsset": "The asset you are trying to upload already exists on the blockchain. Please try again or contact support.", "canNotStartCamera": "Sorry, we encountered an issue while starting the camera. We apologize for the inconvenience. If the problem persists, please report the issue to our developers through the 'Contact Developers' section on the app's support page. Your feedback will help us improve the app and resolve the issue faster. Thank you for your understanding and cooperation.", "fileSizeExeedsLimit": "File size exceeds 25MB limit. Please select a smaller file and try again." - } + }, + "redirectToCaptureDashboard": "Need to upload files?
For a seamless upload experience, please visit https://dashboard.captureapp.xyz." }, "wallets": { "wallets": "Wallets", diff --git a/src/assets/i18n/zh-tw.json b/src/assets/i18n/zh-tw.json index 6a673b905..04a145f67 100644 --- a/src/assets/i18n/zh-tw.json +++ b/src/assets/i18n/zh-tw.json @@ -338,7 +338,8 @@ "duplicateAsset": "您嘗試上傳的資產已有上鏈紀錄,請重新嘗試,或聯繫開發團隊取得協助。", "canNotStartCamera": "很抱歉,我們在啟動相機時遇到問題。對於造成的不便,我們深感抱歉。如果問題持續存在,請透過應用程式支援頁面的「聯絡開發人員」區域向我們的開發人員報告問題。您的反饋將有助於我們改善應用程式並更快地解決問題。感謝您的理解和配合。", "fileSizeExeedsLimit": "檔案大小超過25MB的限制,請選擇較小的檔案並重試。" - } + }, + "redirectToCaptureDashboard": "為提供更好的上傳體驗,建議使用 https://dashboard.captureapp.xyz。" }, "wallets": { "wallets": "錢包", From 64a408f7616f4d5ec46bd775a71ea320ee2cfd99 Mon Sep 17 00:00:00 2001 From: sultanmyrza Date: Tue, 20 Feb 2024 01:15:01 +0800 Subject: [PATCH 09/18] Add redirect alert to capture dashboard for better upload experience --- .../home/custom-camera/custom-camera.page.html | 4 +++- .../home/custom-camera/custom-camera.page.ts | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/app/features/home/custom-camera/custom-camera.page.html b/src/app/features/home/custom-camera/custom-camera.page.html index 8e439ce53..cb2999e7d 100644 --- a/src/app/features/home/custom-camera/custom-camera.page.html +++ b/src/app/features/home/custom-camera/custom-camera.page.html @@ -100,7 +100,9 @@